Merge "DO NOT MERGE: Downbranch merge conflict [Output Switcher] Behavior improvement" into tm-dev

This commit is contained in:
Shaowei Shen
2022-05-03 13:49:43 +00:00
committed by Android (Google) Code Review
5 changed files with 126 additions and 55 deletions

View File

@@ -46,8 +46,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -56,7 +54,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
@RequiresApi(Build.VERSION_CODES.R)
public class LocalMediaManager implements BluetoothCallback {
private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder();
private static final String TAG = "LocalMediaManager";
private static final int MAX_DISCONNECTED_DEVICE_NUM = 5;
@@ -65,13 +62,15 @@ public class LocalMediaManager implements BluetoothCallback {
MediaDeviceState.STATE_CONNECTING,
MediaDeviceState.STATE_DISCONNECTED,
MediaDeviceState.STATE_CONNECTING_FAILED,
MediaDeviceState.STATE_SELECTED})
MediaDeviceState.STATE_SELECTED,
MediaDeviceState.STATE_GROUPING})
public @interface MediaDeviceState {
int STATE_CONNECTED = 0;
int STATE_CONNECTING = 1;
int STATE_DISCONNECTED = 2;
int STATE_CONNECTING_FAILED = 3;
int STATE_SELECTED = 4;
int STATE_GROUPING = 5;
}
private final Collection<DeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
@@ -322,6 +321,7 @@ public class LocalMediaManager implements BluetoothCallback {
* @return If add device successful return {@code true}, otherwise return {@code false}
*/
public boolean addDeviceToPlayMedia(MediaDevice device) {
device.setState(MediaDeviceState.STATE_GROUPING);
return mInfoMediaManager.addDeviceToPlayMedia(device);
}
@@ -332,6 +332,7 @@ public class LocalMediaManager implements BluetoothCallback {
* @return If device stop successful return {@code true}, otherwise return {@code false}
*/
public boolean removeDeviceFromPlayMedia(MediaDevice device) {
device.setState(MediaDeviceState.STATE_GROUPING);
return mInfoMediaManager.removeDeviceFromPlayMedia(device);
}
@@ -524,7 +525,6 @@ public class LocalMediaManager implements BluetoothCallback {
@Override
public void onDeviceListAdded(List<MediaDevice> devices) {
synchronized (mMediaDevicesLock) {
Collections.sort(devices, COMPARATOR);
mMediaDevices.clear();
mMediaDevices.addAll(devices);
// Add disconnected bluetooth devices only when phone output device is available.

View File

@@ -39,6 +39,7 @@
android:visibility="gone"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:background="@null"
android:progressDrawable="@drawable/media_output_dialog_seekbar_background"
android:thumb="@null"
android:layout_width="match_parent"

View File

@@ -166,6 +166,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
true /* showSubtitle */, true /* showStatus */);
mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
} else if (device.getState() == MediaDeviceState.STATE_GROUPING) {
mProgressBar.getIndeterminateDrawable().setColorFilter(
new PorterDuffColorFilter(
mController.getColorItemContent(),
PorterDuff.Mode.SRC_IN));
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
false /* showSeekBar*/,
true /* showProgressBar */, false /* showStatus */);
} else if (mController.getSelectedMediaDevice().size() > 1
&& isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
mTitleText.setTextColor(mController.getColorItemContent());

View File

@@ -184,6 +184,19 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
};
private class LayoutManagerWrapper extends LinearLayoutManager {
LayoutManagerWrapper(Context context) {
super(context);
}
@Override
public void onLayoutCompleted(RecyclerView.State state) {
super.onLayoutCompleted(state);
mMediaOutputController.setRefreshing(false);
mMediaOutputController.refreshDataSetIfNeeded();
}
}
public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender,
MediaOutputController mediaOutputController) {
super(context, R.style.Theme_SystemUI_Dialog_Media);
@@ -192,7 +205,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mContext = getContext();
mBroadcastSender = broadcastSender;
mMediaOutputController = mediaOutputController;
mLayoutManager = new LinearLayoutManager(mContext);
mLayoutManager = new LayoutManagerWrapper(mContext);
mListMaxHeight = context.getResources().getDimensionPixelSize(
R.dimen.media_output_dialog_list_max_height);
mExecutor = Executors.newSingleThreadExecutor();
@@ -274,6 +287,10 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
void refresh(boolean deviceSetChanged) {
if (mMediaOutputController.isRefreshing()) {
return;
}
mMediaOutputController.setRefreshing(true);
// Update header icon
final int iconRes = getHeaderIconRes();
final IconCompat iconCompat = getHeaderIcon();

View File

@@ -81,6 +81,8 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -108,11 +110,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final CommonNotifCollection mNotifCollection;
private final Object mMediaDevicesLock = new Object();
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>();
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager;
private final Map<String, Integer> mNearbyDeviceInfoMap = new ConcurrentHashMap<>();
private boolean mIsRefreshing = false;
private boolean mNeedRefresh = false;
private MediaController mMediaController;
@VisibleForTesting
Callback mCallback;
@@ -172,7 +178,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
void start(@NonNull Callback cb) {
mMediaDevices.clear();
synchronized (mMediaDevicesLock) {
mCachedMediaDevices.clear();
mMediaDevices.clear();
}
mNearbyDeviceInfoMap.clear();
if (mNearbyMediaDevicesManager != null) {
mNearbyMediaDevicesManager.registerNearbyDevicesCallback(this);
@@ -211,6 +220,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
return routerParams != null && !routerParams.isMediaTransferReceiverEnabled();
}
void setRefreshing(boolean refreshing) {
mIsRefreshing = refreshing;
}
boolean isRefreshing() {
return mIsRefreshing;
}
void stop() {
if (mMediaController != null) {
mMediaController.unregisterCallback(mCb);
@@ -219,7 +236,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
mLocalMediaManager.unregisterCallback(this);
mLocalMediaManager.stopScan();
}
mMediaDevices.clear();
synchronized (mMediaDevicesLock) {
mCachedMediaDevices.clear();
mMediaDevices.clear();
}
if (mNearbyMediaDevicesManager != null) {
mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this);
}
@@ -228,15 +248,23 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
buildMediaDevices(devices);
mCallback.onDeviceListChanged();
if (mMediaDevices.isEmpty() || !mIsRefreshing) {
buildMediaDevices(devices);
mCallback.onDeviceListChanged();
} else {
synchronized (mMediaDevicesLock) {
mNeedRefresh = true;
mCachedMediaDevices.clear();
mCachedMediaDevices.addAll(devices);
}
}
}
@Override
public void onSelectedDeviceStateChanged(MediaDevice device,
@LocalMediaManager.MediaDeviceState int state) {
mCallback.onRouteChanged();
mMetricLogger.logOutputSuccess(device.toString(), mMediaDevices);
mMetricLogger.logOutputSuccess(device.toString(), new ArrayList<>(mMediaDevices));
}
@Override
@@ -247,7 +275,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
@Override
public void onRequestFailed(int reason) {
mCallback.onRouteChanged();
mMetricLogger.logOutputFailure(mMediaDevices, reason);
mMetricLogger.logOutputFailure(new ArrayList<>(mMediaDevices), reason);
}
Drawable getAppSourceIcon() {
@@ -399,6 +427,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
}
void refreshDataSetIfNeeded() {
if (mNeedRefresh) {
buildMediaDevices(mCachedMediaDevices);
mCallback.onDeviceListChanged();
mNeedRefresh = false;
}
}
public int getColorConnectedItemBackground() {
return mColorConnectedItemBackground;
}
@@ -432,50 +468,55 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
private void buildMediaDevices(List<MediaDevice> devices) {
// For the first time building list, to make sure the top device is the connected device.
if (mMediaDevices.isEmpty()) {
final MediaDevice connectedMediaDevice = getCurrentConnectedMediaDevice();
if (connectedMediaDevice == null) {
if (DEBUG) {
Log.d(TAG, "No connected media device.");
synchronized (mMediaDevicesLock) {
attachRangeInfo(devices);
Collections.sort(devices, Comparator.naturalOrder());
// For the first time building list, to make sure the top device is the connected
// device.
if (mMediaDevices.isEmpty()) {
final MediaDevice connectedMediaDevice = getCurrentConnectedMediaDevice();
if (connectedMediaDevice == null) {
if (DEBUG) {
Log.d(TAG, "No connected media device.");
}
mMediaDevices.addAll(devices);
return;
}
for (MediaDevice device : devices) {
if (TextUtils.equals(device.getId(), connectedMediaDevice.getId())) {
mMediaDevices.add(0, device);
} else {
mMediaDevices.add(device);
}
}
mMediaDevices.addAll(devices);
return;
}
for (MediaDevice device : devices) {
if (TextUtils.equals(device.getId(), connectedMediaDevice.getId())) {
mMediaDevices.add(0, device);
} else {
mMediaDevices.add(device);
// To keep the same list order
final List<MediaDevice> targetMediaDevices = new ArrayList<>();
for (MediaDevice originalDevice : mMediaDevices) {
for (MediaDevice newDevice : devices) {
if (TextUtils.equals(originalDevice.getId(), newDevice.getId())) {
targetMediaDevices.add(newDevice);
break;
}
}
}
return;
}
// To keep the same list order
final Collection<MediaDevice> targetMediaDevices = new ArrayList<>();
for (MediaDevice originalDevice : mMediaDevices) {
for (MediaDevice newDevice : devices) {
if (TextUtils.equals(originalDevice.getId(), newDevice.getId())) {
targetMediaDevices.add(newDevice);
break;
}
if (targetMediaDevices.size() != devices.size()) {
devices.removeAll(targetMediaDevices);
targetMediaDevices.addAll(devices);
}
mMediaDevices.clear();
mMediaDevices.addAll(targetMediaDevices);
}
if (targetMediaDevices.size() != devices.size()) {
devices.removeAll(targetMediaDevices);
targetMediaDevices.addAll(devices);
}
mMediaDevices.clear();
mMediaDevices.addAll(targetMediaDevices);
attachRangeInfo();
}
private void attachRangeInfo() {
for (MediaDevice mediaDevice : mMediaDevices) {
private void attachRangeInfo(List<MediaDevice> devices) {
for (MediaDevice mediaDevice : devices) {
if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) {
mediaDevice.setRangeZone(mNearbyDeviceInfoMap.get(mediaDevice.getId()));
}
}
}
List<MediaDevice> getGroupMediaDevices() {
@@ -609,26 +650,30 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
}
boolean isTransferring() {
for (MediaDevice device : mMediaDevices) {
if (device.getState() == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
return true;
synchronized (mMediaDevicesLock) {
for (MediaDevice device : mMediaDevices) {
if (device.getState() == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
return true;
}
}
}
return false;
}
boolean isZeroMode() {
if (mMediaDevices.size() == 1) {
final MediaDevice device = mMediaDevices.iterator().next();
// Add "pair new" only when local output device exists
final int type = device.getDeviceType();
if (type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE) {
return true;
synchronized (mMediaDevicesLock) {
if (mMediaDevices.size() == 1) {
final MediaDevice device = mMediaDevices.iterator().next();
// Add "pair new" only when local output device exists
final int type = device.getDeviceType();
if (type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE) {
return true;
}
}
return false;
}
return false;
}
void launchBluetoothPairing(View view) {