Merge "[Output Switcher] Update Volume control in Output Switcher" into tm-qpr-dev am: 951ceea51c am: b9d3d14757

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20607486

Change-Id: I7a3a8aa64993210bd8e3037aad763e17cf993b40
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Shaowei Shen
2022-12-08 23:43:02 +00:00
committed by Automerger Merge Worker
15 changed files with 426 additions and 42 deletions

View File

@@ -17,7 +17,10 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="28dp" />
<corners
android:bottomRightRadius="28dp"
android:topRightRadius="28dp"
/>
<solid android:color="@android:color/transparent" />
<size
android:height="64dp"/>

View File

@@ -0,0 +1,27 @@
<!--
~ Copyright (C) 2022 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M40.65,45.2 L34.05,38.6Q32.65,39.6 31.025,40.325Q29.4,41.05 27.65,41.45V38.35Q28.8,38 29.875,37.575Q30.95,37.15 31.9,36.45L23.65,28.15V40L13.65,30H5.65V18H13.45L2.45,7L4.6,4.85L42.8,43ZM38.85,33.6 L36.7,31.45Q37.7,29.75 38.175,27.85Q38.65,25.95 38.65,23.95Q38.65,18.8 35.65,14.725Q32.65,10.65 27.65,9.55V6.45Q33.85,7.85 37.75,12.725Q41.65,17.6 41.65,23.95Q41.65,26.5 40.95,28.95Q40.25,31.4 38.85,33.6ZM32.15,26.9 L27.65,22.4V15.9Q30,17 31.325,19.2Q32.65,21.4 32.65,24Q32.65,24.75 32.525,25.475Q32.4,26.2 32.15,26.9ZM23.65,18.4 L18.45,13.2 23.65,8ZM20.65,32.7V25.2L16.45,21H8.65V27H14.95ZM18.55,23.1Z"/>
</vector>

View File

@@ -0,0 +1,25 @@
<!--
~ Copyright (C) 2022 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">
<corners
android:bottomLeftRadius="28dp"
android:topLeftRadius="28dp"
android:bottomRightRadius="0dp"
android:topRightRadius="0dp"/>
<solid android:color="@color/media_dialog_item_background" />
</shape>

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/device_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="12dp">
<FrameLayout
android:id="@+id/item_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/media_output_item_background"
android:layout_gravity="center_vertical|start">
<com.android.systemui.media.dialog.MediaOutputSeekbar
android:id="@+id/volume_seekbar"
android:splitTrack="false"
android:visibility="gone"
android:paddingStart="64dp"
android:paddingEnd="0dp"
android:background="@null"
android:contentDescription="@string/media_output_dialog_accessibility_seekbar"
android:progressDrawable="@drawable/media_output_dialog_seekbar_background"
android:thumb="@null"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
<FrameLayout
android:id="@+id/icon_area"
android:layout_width="64dp"
android:layout_height="64dp"
android:background="@drawable/media_output_title_icon_area"
android:layout_gravity="center_vertical|start">
<ImageView
android:id="@+id/title_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:animateLayoutChanges="true"
android:layout_gravity="center"/>
<TextView
android:id="@+id/volume_value"
android:animateLayoutChanges="true"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="16sp"
android:visibility="gone"/>
</FrameLayout>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="72dp"
android:layout_marginEnd="56dp"
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="16sp"/>
<LinearLayout
android:id="@+id/two_line_layout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_height="48dp"
android:layout_marginEnd="56dp"
android:layout_marginStart="72dp">
<TextView
android:id="@+id/two_line_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textColor="@color/media_dialog_item_main_content"
android:textSize="16sp"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/media_dialog_item_main_content"
android:textSize="14sp"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:visibility="gone"/>
</LinearLayout>
<ProgressBar
android:id="@+id/volume_indeterminate_progress"
style="?android:attr/progressBarStyleSmallTitle"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:indeterminate="true"
android:layout_gravity="end|center"
android:indeterminateOnly="true"
android:visibility="gone"/>
<ImageView
android:id="@+id/media_output_item_status"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:indeterminate="true"
android:layout_gravity="end|center"
android:indeterminateOnly="true"
android:importantForAccessibility="no"
android:visibility="gone"/>
<LinearLayout
android:id="@+id/end_action_area"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="48dp"
android:layout_height="64dp"
android:layout_gravity="end|center"
android:gravity="center_vertical">
<CheckBox
android:id="@+id/check_box"
android:focusable="false"
android:importantForAccessibility="no"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:layout_gravity="end"
android:button="@drawable/ic_circle_check_box"
android:visibility="gone"
/>
</LinearLayout>
</FrameLayout>
</LinearLayout>

View File

@@ -2481,7 +2481,7 @@
<!-- Controls menu, edit [CHAR_LIMIT=30] -->
<string name="controls_menu_edit">Edit controls</string>
<!-- Title for the media output group dialog with media related devices [CHAR LIMIT=50] -->
<!-- Title for the media output dialog with media related devices [CHAR LIMIT=50] -->
<string name="media_output_dialog_add_output">Add outputs</string>
<!-- Title for the media output slice with group devices [CHAR LIMIT=50] -->
<string name="media_output_dialog_group">Group</string>
@@ -2505,6 +2505,8 @@
<string name="media_output_dialog_accessibility_title">Available devices for audio output.</string>
<!-- Accessibility text describing purpose of seekbar in media output dialog. [CHAR LIMIT=NONE] -->
<string name="media_output_dialog_accessibility_seekbar">Volume</string>
<!-- Summary for media output volume of a device in percentage [CHAR LIMIT=NONE] -->
<string name="media_output_dialog_volume_percentage"><xliff:g id="percentage" example="10">%1$d</xliff:g>%%</string>
<!-- Media Output Broadcast Dialog -->
<!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->

View File

@@ -435,6 +435,11 @@ object Flags {
val WARN_ON_BLOCKING_BINDER_TRANSACTIONS =
unreleasedFlag(2400, "warn_on_blocking_binder_transactions")
// 2500 - output switcher
// TODO(b/261538825): Tracking Bug
@JvmField
val OUTPUT_SWITCHER_ADVANCED_LAYOUT = unreleasedFlag(2500, "output_switcher_advanced_layout")
// TODO(b259590361): Tracking bug
val EXPERIMENTAL_FLAG = unreleasedFlag(2, "exp_flag_release")
}

View File

@@ -16,7 +16,6 @@
package com.android.systemui.media.dialog;
import android.annotation.DrawableRes;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
@@ -122,17 +121,19 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
// Set different layout for each device
if (device.isMutingExpectedDevice()
&& !mController.isCurrentConnectedDeviceRemote()) {
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
if (!mController.isAdvancedLayoutSupported()) {
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
}
initMutingExpectedDevice();
mCurrentActivePosition = position;
updateContainerClickListener(v -> onItemClick(v, device));
updateFullItemClickListener(v -> onItemClick(v, device));
setSingleLineLayout(getItemTitle(device));
} else if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
setUpDeviceIcon(device);
updateConnectionFailedStatusIcon();
mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
updateContainerClickListener(v -> onItemClick(v, device));
updateFullItemClickListener(v -> onItemClick(v, device));
setTwoLineLayout(device, false /* bFocused */, false /* showSeekBar */,
false /* showProgressBar */, true /* showSubtitle */,
true /* showStatus */);
@@ -146,8 +147,10 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
&& isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
boolean isDeviceDeselectable = isDeviceIncluded(
mController.getDeselectableMediaDevice(), device);
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
if (!mController.isAdvancedLayoutSupported()) {
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
}
updateGroupableCheckBox(true, isDeviceDeselectable, device);
updateEndClickArea(device, isDeviceDeselectable);
setUpContentDescriptionForView(mContainerLayout, false, device);
@@ -161,7 +164,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
&& !mController.isCurrentConnectedDeviceRemote()) {
// mark as disconnected and set special click listener
setUpDeviceIcon(device);
updateContainerClickListener(v -> cancelMuteAwaitConnection());
updateFullItemClickListener(v -> cancelMuteAwaitConnection());
setSingleLineLayout(getItemTitle(device));
} else {
updateTitleIcon(R.drawable.media_output_icon_volume,
@@ -176,14 +179,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
} else if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
setUpDeviceIcon(device);
updateGroupableCheckBox(false, true, device);
updateContainerClickListener(v -> onGroupActionTriggered(true, device));
updateFullItemClickListener(v -> onGroupActionTriggered(true, device));
setSingleLineLayout(getItemTitle(device), false /* showSeekBar */,
false /* showProgressBar */, true /* showCheckBox */,
true /* showEndTouchArea */);
} else {
setUpDeviceIcon(device);
setSingleLineLayout(getItemTitle(device));
updateContainerClickListener(v -> onItemClick(v, device));
updateFullItemClickListener(v -> onItemClick(v, device));
}
}
}
@@ -228,13 +231,9 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
setCheckBoxColor(mCheckBox, mController.getColorItemContent());
}
private void updateTitleIcon(@DrawableRes int id, int color) {
mTitleIcon.setImageDrawable(mContext.getDrawable(id));
mTitleIcon.setColorFilter(color);
}
private void updateContainerClickListener(View.OnClickListener listener) {
private void updateFullItemClickListener(View.OnClickListener listener) {
mContainerLayout.setOnClickListener(listener);
updateIconAreaClickListener(listener);
}
@Override
@@ -246,6 +245,11 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
final Drawable addDrawable = mContext.getDrawable(R.drawable.ic_add);
mTitleIcon.setImageDrawable(addDrawable);
mTitleIcon.setColorFilter(mController.getColorItemContent());
if (mController.isAdvancedLayoutSupported()) {
mIconAreaLayout.getBackground().setColorFilter(
new PorterDuffColorFilter(mController.getColorItemBackground(),
PorterDuff.Mode.SRC_IN));
}
mContainerLayout.setOnClickListener(mController::launchBluetoothPairing);
}
}

View File

@@ -16,8 +16,11 @@
package com.android.systemui.media.dialog;
import static com.android.systemui.media.dialog.MediaOutputSeekbar.VOLUME_PERCENTAGE_SCALE_SIZE;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.DrawableRes;
import android.app.WallpaperColors;
import android.content.Context;
import android.graphics.PorterDuff;
@@ -80,8 +83,9 @@ public abstract class MediaOutputBaseAdapter extends
public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
mContext = viewGroup.getContext();
mHolderView = LayoutInflater.from(mContext).inflate(R.layout.media_output_list_item,
viewGroup, false);
mHolderView = LayoutInflater.from(mContext).inflate(
mController.isAdvancedLayoutSupported() ? R.layout.media_output_list_item_advanced
: R.layout.media_output_list_item, viewGroup, false);
return null;
}
@@ -131,9 +135,11 @@ public abstract class MediaOutputBaseAdapter extends
final LinearLayout mContainerLayout;
final FrameLayout mItemLayout;
final FrameLayout mIconAreaLayout;
final TextView mTitleText;
final TextView mTwoLineTitleText;
final TextView mSubTitleText;
final TextView mVolumeValueText;
final ImageView mTitleIcon;
final ProgressBar mProgressBar;
final MediaOutputSeekbar mSeekBar;
@@ -159,6 +165,13 @@ public abstract class MediaOutputBaseAdapter extends
mStatusIcon = view.requireViewById(R.id.media_output_item_status);
mCheckBox = view.requireViewById(R.id.check_box);
mEndTouchArea = view.requireViewById(R.id.end_action_area);
if (mController.isAdvancedLayoutSupported()) {
mVolumeValueText = view.requireViewById(R.id.volume_value);
mIconAreaLayout = view.requireViewById(R.id.icon_area);
} else {
mVolumeValueText = null;
mIconAreaLayout = null;
}
initAnimator();
}
@@ -170,9 +183,14 @@ public abstract class MediaOutputBaseAdapter extends
mEndTouchArea.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
mContainerLayout.setOnClickListener(null);
mContainerLayout.setContentDescription(null);
mTitleIcon.setOnClickListener(null);
mTitleText.setTextColor(mController.getColorItemContent());
mSubTitleText.setTextColor(mController.getColorItemContent());
mTwoLineTitleText.setTextColor(mController.getColorItemContent());
if (mController.isAdvancedLayoutSupported()) {
mIconAreaLayout.setOnClickListener(null);
mVolumeValueText.setTextColor(mController.getColorItemContent());
}
mSeekBar.getProgressDrawable().setColorFilter(
new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
PorterDuff.Mode.SRC_IN));
@@ -203,13 +221,28 @@ public abstract class MediaOutputBaseAdapter extends
.findDrawableByLayerId(android.R.id.progress);
final GradientDrawable progressDrawable =
(GradientDrawable) clipDrawable.getDrawable();
progressDrawable.setCornerRadius(mController.getActiveRadius());
if (mController.isAdvancedLayoutSupported()) {
progressDrawable.setCornerRadii(
new float[]{0, 0, mController.getActiveRadius(),
mController.getActiveRadius(),
mController.getActiveRadius(),
mController.getActiveRadius(), 0, 0});
} else {
progressDrawable.setCornerRadius(mController.getActiveRadius());
}
}
}
mItemLayout.getBackground().setColorFilter(new PorterDuffColorFilter(
isActive ? mController.getColorConnectedItemBackground()
: mController.getColorItemBackground(),
PorterDuff.Mode.SRC_IN));
if (mController.isAdvancedLayoutSupported()) {
mIconAreaLayout.getBackground().setColorFilter(new PorterDuffColorFilter(
showSeekBar ? mController.getColorSeekbarProgress()
: showProgressBar ? mController.getColorConnectedItemBackground()
: mController.getColorItemBackground(),
PorterDuff.Mode.SRC_IN));
}
mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
mSeekBar.setAlpha(1);
mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);
@@ -263,42 +296,134 @@ public abstract class MediaOutputBaseAdapter extends
final int currentVolume = device.getCurrentVolume();
if (mSeekBar.getVolume() != currentVolume) {
if (isCurrentSeekbarInvisible && !mIsInitVolumeFirstTime) {
if (mController.isAdvancedLayoutSupported()) {
updateTitleIcon(currentVolume == 0 ? R.drawable.media_output_icon_volume_off
: R.drawable.media_output_icon_volume,
mController.getColorItemContent());
}
animateCornerAndVolume(mSeekBar.getProgress(),
MediaOutputSeekbar.scaleVolumeToProgress(currentVolume));
} else {
if (!mVolumeAnimator.isStarted()) {
if (mController.isAdvancedLayoutSupported()) {
int percentage =
(int) ((double) currentVolume * VOLUME_PERCENTAGE_SCALE_SIZE
/ (double) mSeekBar.getMax());
if (percentage == 0) {
updateMutedVolumeIcon();
} else {
updateUnmutedVolumeIcon();
}
}
mSeekBar.setVolume(currentVolume);
}
}
} else if (mController.isAdvancedLayoutSupported() && currentVolume == 0) {
mSeekBar.resetVolume();
updateMutedVolumeIcon();
}
if (mIsInitVolumeFirstTime) {
mIsInitVolumeFirstTime = false;
}
if (mController.isAdvancedLayoutSupported()) {
updateIconAreaClickListener((v) -> {
mSeekBar.resetVolume();
mController.adjustVolume(device, 0);
updateMutedVolumeIcon();
});
}
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (device == null || !fromUser) {
return;
}
int currentVolume = MediaOutputSeekbar.scaleProgressToVolume(progress);
int progressToVolume = MediaOutputSeekbar.scaleProgressToVolume(progress);
int deviceVolume = device.getCurrentVolume();
if (currentVolume != deviceVolume) {
mController.adjustVolume(device, currentVolume);
if (mController.isAdvancedLayoutSupported()) {
int percentage =
(int) ((double) progressToVolume * VOLUME_PERCENTAGE_SCALE_SIZE
/ (double) seekBar.getMax());
mVolumeValueText.setText(mContext.getResources().getString(
R.string.media_output_dialog_volume_percentage, percentage));
mVolumeValueText.setVisibility(View.VISIBLE);
}
if (progressToVolume != deviceVolume) {
mController.adjustVolume(device, progressToVolume);
if (mController.isAdvancedLayoutSupported() && deviceVolume == 0) {
updateUnmutedVolumeIcon();
}
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
if (mController.isAdvancedLayoutSupported()) {
mTitleIcon.setVisibility(View.INVISIBLE);
mVolumeValueText.setVisibility(View.VISIBLE);
}
mIsDragging = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mController.isAdvancedLayoutSupported()) {
int currentVolume = MediaOutputSeekbar.scaleProgressToVolume(
seekBar.getProgress());
int percentage =
(int) ((double) currentVolume * VOLUME_PERCENTAGE_SCALE_SIZE
/ (double) seekBar.getMax());
if (percentage == 0) {
seekBar.setProgress(0);
updateMutedVolumeIcon();
} else {
updateUnmutedVolumeIcon();
}
mTitleIcon.setVisibility(View.VISIBLE);
mVolumeValueText.setVisibility(View.GONE);
}
mIsDragging = false;
}
});
}
void updateMutedVolumeIcon() {
updateTitleIcon(R.drawable.media_output_icon_volume_off,
mController.getColorItemContent());
final GradientDrawable iconAreaBackgroundDrawable =
(GradientDrawable) mIconAreaLayout.getBackground();
iconAreaBackgroundDrawable.setCornerRadius(mController.getActiveRadius());
}
void updateUnmutedVolumeIcon() {
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
final GradientDrawable iconAreaBackgroundDrawable =
(GradientDrawable) mIconAreaLayout.getBackground();
iconAreaBackgroundDrawable.setCornerRadii(new float[]{
mController.getActiveRadius(),
mController.getActiveRadius(),
0, 0, 0, 0, mController.getActiveRadius(), mController.getActiveRadius()
});
}
void updateTitleIcon(@DrawableRes int id, int color) {
mTitleIcon.setImageDrawable(mContext.getDrawable(id));
mTitleIcon.setColorFilter(color);
if (mController.isAdvancedLayoutSupported()) {
mIconAreaLayout.getBackground().setColorFilter(
new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
PorterDuff.Mode.SRC_IN));
}
}
void updateIconAreaClickListener(View.OnClickListener listener) {
if (mController.isAdvancedLayoutSupported()) {
mIconAreaLayout.setOnClickListener(listener);
}
mTitleIcon.setOnClickListener(listener);
}
void initMutingExpectedDevice() {
disableSeekBar();
final Drawable backgroundDrawable = mContext.getDrawable(
@@ -316,11 +441,26 @@ public abstract class MediaOutputBaseAdapter extends
final ClipDrawable clipDrawable =
(ClipDrawable) ((LayerDrawable) mSeekBar.getProgressDrawable())
.findDrawableByLayerId(android.R.id.progress);
final GradientDrawable progressDrawable = (GradientDrawable) clipDrawable.getDrawable();
final GradientDrawable targetBackgroundDrawable =
(GradientDrawable) (mController.isAdvancedLayoutSupported()
? mIconAreaLayout.getBackground()
: clipDrawable.getDrawable());
mCornerAnimator.addUpdateListener(animation -> {
float value = (float) animation.getAnimatedValue();
layoutBackgroundDrawable.setCornerRadius(value);
progressDrawable.setCornerRadius(value);
if (mController.isAdvancedLayoutSupported()) {
if (toProgress == 0) {
targetBackgroundDrawable.setCornerRadius(value);
} else {
targetBackgroundDrawable.setCornerRadii(new float[]{
value,
value,
0, 0, 0, 0, value, value
});
}
} else {
targetBackgroundDrawable.setCornerRadius(value);
}
});
mVolumeAnimator.setIntValues(fromProgress, toProgress);
mVolumeAnimator.start();

View File

@@ -26,6 +26,7 @@ import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.media.nearby.NearbyMediaDevicesManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -47,7 +48,8 @@ class MediaOutputBroadcastDialogFactory @Inject constructor(
private val nearbyMediaDevicesManagerOptional: Optional<NearbyMediaDevicesManager>,
private val audioManager: AudioManager,
private val powerExemptionManager: PowerExemptionManager,
private val keyGuardManager: KeyguardManager
private val keyGuardManager: KeyguardManager,
private val featureFlags: FeatureFlags
) {
var mediaOutputBroadcastDialog: MediaOutputBroadcastDialog? = null
@@ -59,7 +61,7 @@ class MediaOutputBroadcastDialogFactory @Inject constructor(
val controller = MediaOutputController(context, packageName,
mediaSessionManager, lbm, starter, notifCollection,
dialogLaunchAnimator, nearbyMediaDevicesManagerOptional, audioManager,
powerExemptionManager, keyGuardManager)
powerExemptionManager, keyGuardManager, featureFlags)
val dialog =
MediaOutputBroadcastDialog(context, aboveStatusBar, broadcastSender, controller)
mediaOutputBroadcastDialog = dialog

View File

@@ -73,6 +73,8 @@ import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.plugins.ActivityStarter;
@@ -147,6 +149,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
private int mColorDialogBackground;
private float mInactiveRadius;
private float mActiveRadius;
private FeatureFlags mFeatureFlags;
public enum BroadcastNotifyDialog {
ACTION_FIRST_LAUNCH,
@@ -162,7 +165,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
Optional<NearbyMediaDevicesManager> nearbyMediaDevicesManagerOptional,
AudioManager audioManager,
PowerExemptionManager powerExemptionManager,
KeyguardManager keyGuardManager) {
KeyguardManager keyGuardManager,
FeatureFlags featureFlags) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
@@ -172,6 +176,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
mAudioManager = audioManager;
mPowerExemptionManager = powerExemptionManager;
mKeyGuardManager = keyGuardManager;
mFeatureFlags = featureFlags;
InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm);
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
@@ -599,6 +604,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
currentConnectedMediaDevice);
}
public boolean isAdvancedLayoutSupported() {
return mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT);
}
List<MediaDevice> getGroupMediaDevices() {
final List<MediaDevice> selectedDevices = getSelectedMediaDevice();
final List<MediaDevice> selectableDevices = getSelectableMediaDevice();
@@ -792,7 +801,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
mMediaSessionManager, mLocalBluetoothManager, mActivityStarter,
mNotifCollection, mDialogLaunchAnimator, Optional.of(mNearbyMediaDevicesManager),
mAudioManager, mPowerExemptionManager, mKeyGuardManager);
mAudioManager, mPowerExemptionManager, mKeyGuardManager, mFeatureFlags);
MediaOutputBroadcastDialog dialog = new MediaOutputBroadcastDialog(mContext, true,
broadcastSender, controller);
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);

View File

@@ -31,6 +31,7 @@ import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.media.nearby.NearbyMediaDevicesManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.flags.FeatureFlags
import java.util.Optional
import javax.inject.Inject
@@ -49,7 +50,8 @@ class MediaOutputDialogFactory @Inject constructor(
private val nearbyMediaDevicesManagerOptional: Optional<NearbyMediaDevicesManager>,
private val audioManager: AudioManager,
private val powerExemptionManager: PowerExemptionManager,
private val keyGuardManager: KeyguardManager
private val keyGuardManager: KeyguardManager,
private val featureFlags: FeatureFlags
) {
companion object {
private const val INTERACTION_JANK_TAG = "media_output"
@@ -65,7 +67,7 @@ class MediaOutputDialogFactory @Inject constructor(
context, packageName,
mediaSessionManager, lbm, starter, notifCollection,
dialogLaunchAnimator, nearbyMediaDevicesManagerOptional, audioManager,
powerExemptionManager, keyGuardManager)
powerExemptionManager, keyGuardManager, featureFlags)
val dialog =
MediaOutputDialog(context, aboveStatusBar, broadcastSender, controller, uiEventLogger)
mediaOutputDialog = dialog

View File

@@ -26,6 +26,7 @@ import android.widget.SeekBar;
*/
public class MediaOutputSeekbar extends SeekBar {
private static final int SCALE_SIZE = 1000;
public static final int VOLUME_PERCENTAGE_SCALE_SIZE = 100000;
public MediaOutputSeekbar(Context context, AttributeSet attrs) {
super(context, attrs);

View File

@@ -51,6 +51,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -89,6 +90,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
private final AudioManager mAudioManager = mock(AudioManager.class);
private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
private FeatureFlags mFlags = mock(FeatureFlags.class);
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
@@ -121,7 +123,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mBroadcastSender,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());

View File

@@ -62,6 +62,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -110,6 +111,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private FeatureFlags mFlags = mock(FeatureFlags.class);
private final ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController = mock(
ActivityLaunchAnimator.Controller.class);
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
@@ -141,7 +143,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -194,7 +196,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
mMediaOutputController.start(mCb);
@@ -224,7 +226,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
mMediaOutputController.start(mCb);
@@ -318,7 +320,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
testMediaOutputController.start(mCb);
reset(mCb);
@@ -341,7 +343,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
testMediaOutputController.start(mCb);
reset(mCb);
@@ -377,7 +379,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
LocalMediaManager testLocalMediaManager = spy(testMediaOutputController.mLocalMediaManager);
testMediaOutputController.mLocalMediaManager = testLocalMediaManager;
@@ -394,7 +396,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
LocalMediaManager testLocalMediaManager = spy(testMediaOutputController.mLocalMediaManager);
testMediaOutputController.mLocalMediaManager = testLocalMediaManager;
@@ -671,7 +673,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}

View File

@@ -50,6 +50,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -93,6 +94,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
private final AudioManager mAudioManager = mock(AudioManager.class);
private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
private FeatureFlags mFlags = mock(FeatureFlags.class);
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputDialog mMediaOutputDialog;
@@ -115,7 +117,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager);
mKeyguardManager, mFlags);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
mMediaOutputController, mUiEventLogger);