Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8292f122 authored by Shaowei Shen's avatar Shaowei Shen Committed by Android (Google) Code Review
Browse files

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

parents abe29d73 73706cee
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -46,8 +46,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArrayList;


@@ -56,7 +54,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
 */
 */
@RequiresApi(Build.VERSION_CODES.R)
@RequiresApi(Build.VERSION_CODES.R)
public class LocalMediaManager implements BluetoothCallback {
public class LocalMediaManager implements BluetoothCallback {
    private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder();
    private static final String TAG = "LocalMediaManager";
    private static final String TAG = "LocalMediaManager";
    private static final int MAX_DISCONNECTED_DEVICE_NUM = 5;
    private static final int MAX_DISCONNECTED_DEVICE_NUM = 5;


@@ -65,13 +62,15 @@ public class LocalMediaManager implements BluetoothCallback {
            MediaDeviceState.STATE_CONNECTING,
            MediaDeviceState.STATE_CONNECTING,
            MediaDeviceState.STATE_DISCONNECTED,
            MediaDeviceState.STATE_DISCONNECTED,
            MediaDeviceState.STATE_CONNECTING_FAILED,
            MediaDeviceState.STATE_CONNECTING_FAILED,
            MediaDeviceState.STATE_SELECTED})
            MediaDeviceState.STATE_SELECTED,
            MediaDeviceState.STATE_GROUPING})
    public @interface MediaDeviceState {
    public @interface MediaDeviceState {
        int STATE_CONNECTED = 0;
        int STATE_CONNECTED = 0;
        int STATE_CONNECTING = 1;
        int STATE_CONNECTING = 1;
        int STATE_DISCONNECTED = 2;
        int STATE_DISCONNECTED = 2;
        int STATE_CONNECTING_FAILED = 3;
        int STATE_CONNECTING_FAILED = 3;
        int STATE_SELECTED = 4;
        int STATE_SELECTED = 4;
        int STATE_GROUPING = 5;
    }
    }


    private final Collection<DeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
    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}
     * @return If add device successful return {@code true}, otherwise return {@code false}
     */
     */
    public boolean addDeviceToPlayMedia(MediaDevice device) {
    public boolean addDeviceToPlayMedia(MediaDevice device) {
        device.setState(MediaDeviceState.STATE_GROUPING);
        return mInfoMediaManager.addDeviceToPlayMedia(device);
        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}
     * @return If device stop successful return {@code true}, otherwise return {@code false}
     */
     */
    public boolean removeDeviceFromPlayMedia(MediaDevice device) {
    public boolean removeDeviceFromPlayMedia(MediaDevice device) {
        device.setState(MediaDeviceState.STATE_GROUPING);
        return mInfoMediaManager.removeDeviceFromPlayMedia(device);
        return mInfoMediaManager.removeDeviceFromPlayMedia(device);
    }
    }


@@ -524,7 +525,6 @@ public class LocalMediaManager implements BluetoothCallback {
        @Override
        @Override
        public void onDeviceListAdded(List<MediaDevice> devices) {
        public void onDeviceListAdded(List<MediaDevice> devices) {
            synchronized (mMediaDevicesLock) {
            synchronized (mMediaDevicesLock) {
                Collections.sort(devices, COMPARATOR);
                mMediaDevices.clear();
                mMediaDevices.clear();
                mMediaDevices.addAll(devices);
                mMediaDevices.addAll(devices);
                // Add disconnected bluetooth devices only when phone output device is available.
                // Add disconnected bluetooth devices only when phone output device is available.
+1 −0
Original line number Original line Diff line number Diff line
@@ -39,6 +39,7 @@
                android:visibility="gone"
                android:visibility="gone"
                android:paddingStart="0dp"
                android:paddingStart="0dp"
                android:paddingEnd="0dp"
                android:paddingEnd="0dp"
                android:background="@null"
                android:progressDrawable="@drawable/media_output_dialog_seekbar_background"
                android:progressDrawable="@drawable/media_output_dialog_seekbar_background"
                android:thumb="@null"
                android:thumb="@null"
                android:layout_width="match_parent"
                android:layout_width="match_parent"
+8 −0
Original line number Original line Diff line number Diff line
@@ -166,6 +166,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
                            true /* showSubtitle */, true /* showStatus */);
                            true /* showSubtitle */, true /* showStatus */);
                    mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
                    mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
                    mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
                    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
                } else if (mController.getSelectedMediaDevice().size() > 1
                        && isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
                        && isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
                    mTitleText.setTextColor(mController.getColorItemContent());
                    mTitleText.setTextColor(mController.getColorItemContent());
+18 −1
Original line number Original line Diff line number Diff line
@@ -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,
    public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender,
            MediaOutputController mediaOutputController) {
            MediaOutputController mediaOutputController) {
        super(context, R.style.Theme_SystemUI_Dialog_Media);
        super(context, R.style.Theme_SystemUI_Dialog_Media);
@@ -192,7 +205,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
        mContext = getContext();
        mContext = getContext();
        mBroadcastSender = broadcastSender;
        mBroadcastSender = broadcastSender;
        mMediaOutputController = mediaOutputController;
        mMediaOutputController = mediaOutputController;
        mLayoutManager = new LinearLayoutManager(mContext);
        mLayoutManager = new LayoutManagerWrapper(mContext);
        mListMaxHeight = context.getResources().getDimensionPixelSize(
        mListMaxHeight = context.getResources().getDimensionPixelSize(
                R.dimen.media_output_dialog_list_max_height);
                R.dimen.media_output_dialog_list_max_height);
        mExecutor = Executors.newSingleThreadExecutor();
        mExecutor = Executors.newSingleThreadExecutor();
@@ -274,6 +287,10 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
    }
    }


    void refresh(boolean deviceSetChanged) {
    void refresh(boolean deviceSetChanged) {
        if (mMediaOutputController.isRefreshing()) {
            return;
        }
        mMediaOutputController.setRefreshing(true);
        // Update header icon
        // Update header icon
        final int iconRes = getHeaderIconRes();
        final int iconRes = getHeaderIconRes();
        final IconCompat iconCompat = getHeaderIcon();
        final IconCompat iconCompat = getHeaderIcon();
+94 −49
Original line number Original line Diff line number Diff line
@@ -81,6 +81,8 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.nio.charset.StandardCharsets;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Optional;
import java.util.Optional;
@@ -108,11 +110,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
    private final DialogLaunchAnimator mDialogLaunchAnimator;
    private final DialogLaunchAnimator mDialogLaunchAnimator;
    private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
    private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
    private final CommonNotifCollection mNotifCollection;
    private final CommonNotifCollection mNotifCollection;
    private final Object mMediaDevicesLock = new Object();
    @VisibleForTesting
    @VisibleForTesting
    final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
    final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
    final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>();
    private final NearbyMediaDevicesManager mNearbyMediaDevicesManager;
    private final NearbyMediaDevicesManager mNearbyMediaDevicesManager;
    private final Map<String, Integer> mNearbyDeviceInfoMap = new ConcurrentHashMap<>();
    private final Map<String, Integer> mNearbyDeviceInfoMap = new ConcurrentHashMap<>();


    private boolean mIsRefreshing = false;
    private boolean mNeedRefresh = false;
    private MediaController mMediaController;
    private MediaController mMediaController;
    @VisibleForTesting
    @VisibleForTesting
    Callback mCallback;
    Callback mCallback;
@@ -172,7 +178,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
    }
    }


    void start(@NonNull Callback cb) {
    void start(@NonNull Callback cb) {
        synchronized (mMediaDevicesLock) {
            mCachedMediaDevices.clear();
            mMediaDevices.clear();
            mMediaDevices.clear();
        }
        mNearbyDeviceInfoMap.clear();
        mNearbyDeviceInfoMap.clear();
        if (mNearbyMediaDevicesManager != null) {
        if (mNearbyMediaDevicesManager != null) {
            mNearbyMediaDevicesManager.registerNearbyDevicesCallback(this);
            mNearbyMediaDevicesManager.registerNearbyDevicesCallback(this);
@@ -211,6 +220,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
        return routerParams != null && !routerParams.isMediaTransferReceiverEnabled();
        return routerParams != null && !routerParams.isMediaTransferReceiverEnabled();
    }
    }


    void setRefreshing(boolean refreshing) {
        mIsRefreshing = refreshing;
    }

    boolean isRefreshing() {
        return mIsRefreshing;
    }

    void stop() {
    void stop() {
        if (mMediaController != null) {
        if (mMediaController != null) {
            mMediaController.unregisterCallback(mCb);
            mMediaController.unregisterCallback(mCb);
@@ -219,7 +236,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
            mLocalMediaManager.unregisterCallback(this);
            mLocalMediaManager.unregisterCallback(this);
            mLocalMediaManager.stopScan();
            mLocalMediaManager.stopScan();
        }
        }
        synchronized (mMediaDevicesLock) {
            mCachedMediaDevices.clear();
            mMediaDevices.clear();
            mMediaDevices.clear();
        }
        if (mNearbyMediaDevicesManager != null) {
        if (mNearbyMediaDevicesManager != null) {
            mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this);
            mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this);
        }
        }
@@ -228,15 +248,23 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,


    @Override
    @Override
    public void onDeviceListUpdate(List<MediaDevice> devices) {
    public void onDeviceListUpdate(List<MediaDevice> devices) {
        if (mMediaDevices.isEmpty() || !mIsRefreshing) {
            buildMediaDevices(devices);
            buildMediaDevices(devices);
            mCallback.onDeviceListChanged();
            mCallback.onDeviceListChanged();
        } else {
            synchronized (mMediaDevicesLock) {
                mNeedRefresh = true;
                mCachedMediaDevices.clear();
                mCachedMediaDevices.addAll(devices);
            }
        }
    }
    }


    @Override
    @Override
    public void onSelectedDeviceStateChanged(MediaDevice device,
    public void onSelectedDeviceStateChanged(MediaDevice device,
            @LocalMediaManager.MediaDeviceState int state) {
            @LocalMediaManager.MediaDeviceState int state) {
        mCallback.onRouteChanged();
        mCallback.onRouteChanged();
        mMetricLogger.logOutputSuccess(device.toString(), mMediaDevices);
        mMetricLogger.logOutputSuccess(device.toString(), new ArrayList<>(mMediaDevices));
    }
    }


    @Override
    @Override
@@ -247,7 +275,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
    @Override
    @Override
    public void onRequestFailed(int reason) {
    public void onRequestFailed(int reason) {
        mCallback.onRouteChanged();
        mCallback.onRouteChanged();
        mMetricLogger.logOutputFailure(mMediaDevices, reason);
        mMetricLogger.logOutputFailure(new ArrayList<>(mMediaDevices), reason);
    }
    }


    Drawable getAppSourceIcon() {
    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() {
    public int getColorConnectedItemBackground() {
        return mColorConnectedItemBackground;
        return mColorConnectedItemBackground;
    }
    }
@@ -432,7 +468,11 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
    }
    }


    private void buildMediaDevices(List<MediaDevice> devices) {
    private void buildMediaDevices(List<MediaDevice> devices) {
        // For the first time building list, to make sure the top device is the connected 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()) {
            if (mMediaDevices.isEmpty()) {
                final MediaDevice connectedMediaDevice = getCurrentConnectedMediaDevice();
                final MediaDevice connectedMediaDevice = getCurrentConnectedMediaDevice();
                if (connectedMediaDevice == null) {
                if (connectedMediaDevice == null) {
@@ -452,7 +492,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
                return;
                return;
            }
            }
            // To keep the same list order
            // To keep the same list order
        final Collection<MediaDevice> targetMediaDevices = new ArrayList<>();
            final List<MediaDevice> targetMediaDevices = new ArrayList<>();
            for (MediaDevice originalDevice : mMediaDevices) {
            for (MediaDevice originalDevice : mMediaDevices) {
                for (MediaDevice newDevice : devices) {
                for (MediaDevice newDevice : devices) {
                    if (TextUtils.equals(originalDevice.getId(), newDevice.getId())) {
                    if (TextUtils.equals(originalDevice.getId(), newDevice.getId())) {
@@ -467,15 +507,16 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
            }
            }
            mMediaDevices.clear();
            mMediaDevices.clear();
            mMediaDevices.addAll(targetMediaDevices);
            mMediaDevices.addAll(targetMediaDevices);
        attachRangeInfo();
        }
    }
    }


    private void attachRangeInfo() {
    private void attachRangeInfo(List<MediaDevice> devices) {
        for (MediaDevice mediaDevice : mMediaDevices) {
        for (MediaDevice mediaDevice : devices) {
            if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) {
            if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) {
                mediaDevice.setRangeZone(mNearbyDeviceInfoMap.get(mediaDevice.getId()));
                mediaDevice.setRangeZone(mNearbyDeviceInfoMap.get(mediaDevice.getId()));
            }
            }
        }
        }

    }
    }


    List<MediaDevice> getGroupMediaDevices() {
    List<MediaDevice> getGroupMediaDevices() {
@@ -609,15 +650,18 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
    }
    }


    boolean isTransferring() {
    boolean isTransferring() {
        synchronized (mMediaDevicesLock) {
            for (MediaDevice device : mMediaDevices) {
            for (MediaDevice device : mMediaDevices) {
                if (device.getState() == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
                if (device.getState() == LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
                    return true;
                    return true;
                }
                }
            }
            }
        }
        return false;
        return false;
    }
    }


    boolean isZeroMode() {
    boolean isZeroMode() {
        synchronized (mMediaDevicesLock) {
            if (mMediaDevices.size() == 1) {
            if (mMediaDevices.size() == 1) {
                final MediaDevice device = mMediaDevices.iterator().next();
                final MediaDevice device = mMediaDevices.iterator().next();
                // Add "pair new" only when local output device exists
                // Add "pair new" only when local output device exists
@@ -630,6 +674,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
            }
            }
            return false;
            return false;
        }
        }
    }


    void launchBluetoothPairing(View view) {
    void launchBluetoothPairing(View view) {
        ActivityLaunchAnimator.Controller controller =
        ActivityLaunchAnimator.Controller controller =