diff options
| author | 2022-05-03 13:49:43 +0000 | |
|---|---|---|
| committer | 2022-05-03 13:49:43 +0000 | |
| commit | 8292f122d874c2489acca07c85545055cf25e37f (patch) | |
| tree | deab01a8ee3e345b5a83448ebd451627e6888ae9 | |
| parent | abe29d73629bb41d06217ccd077c20d313599b90 (diff) | |
| parent | 73706ceebfc232072b89808694990c6ac71a810d (diff) | |
Merge "DO NOT MERGE: Downbranch merge conflict [Output Switcher] Behavior improvement" into tm-dev
5 files changed, 126 insertions, 55 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index e1a2e8daf971..d6d73046bed3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -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. diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml index daa9c04584ae..f79e534670d8 100644 --- a/packages/SystemUI/res/layout/media_output_list_item.xml +++ b/packages/SystemUI/res/layout/media_output_list_item.xml @@ -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" diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java index 694149a1e6e7..a397f32dcbbf 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -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()); diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java index 22bdacae1bcd..5bb6557c3fe7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -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(); diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index 082f4bc3efe3..e7f97d25fabe 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -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) { |