Loading packages/SystemUI/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -2283,6 +2283,10 @@ <string name="media_output_broadcast_code">Password</string> <!-- Button for change broadcast name and broadcast code [CHAR LIMIT=60] --> <string name="media_output_broadcast_dialog_save">Save</string> <!-- The "starting" text when Broadcast is starting [CHAR LIMIT=60] --> <string name="media_output_broadcast_starting">Starting…</string> <!-- The button text when Broadcast start failed [CHAR LIMIT=60] --> <string name="media_output_broadcast_start_failed">Can\u2019t broadcast</string> <!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]--> <string name="build_number_clip_data_label">Build number</string> Loading packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +153 −28 Original line number Diff line number Diff line Loading @@ -19,7 +19,10 @@ package com.android.systemui.media.dialog; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import android.annotation.NonNull; import android.app.WallpaperColors; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; Loading Loading @@ -59,6 +62,9 @@ import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.statusbar.phone.SystemUIDialog; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * Base dialog for media output UI */ Loading @@ -69,6 +75,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private static final String EMPTY_TITLE = " "; private static final String PREF_NAME = "MediaOutputDialog"; private static final String PREF_IS_LE_BROADCAST_FIRST_LAUNCH = "PrefIsLeBroadcastFirstLaunch"; private static final boolean DEBUG = true; private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final RecyclerView.LayoutManager mLayoutManager; Loading @@ -91,6 +98,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private Button mAppButton; private int mListMaxHeight; private WallpaperColors mWallpaperColors; private Executor mExecutor; MediaOutputBaseAdapter mAdapter; Loading @@ -103,6 +111,79 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements } }; private final BluetoothLeBroadcast.Callback mBroadcastCallback = new BluetoothLeBroadcast.Callback() { @Override public void onBroadcastStarted(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastStarted(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> startLeBroadcastDialog()); } @Override public void onBroadcastStartFailed(int reason) { if (DEBUG) { Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason); } handleLeBroadcastStartFailed(); } @Override public void onBroadcastMetadataChanged(int broadcastId, @NonNull BluetoothLeBroadcastMetadata metadata) { if (DEBUG) { Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId + ", metadata = " + metadata); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastStopped(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastStopped(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastStopFailed(int reason) { if (DEBUG) { Log.d(TAG, "onBroadcastStopFailed(), reason = " + reason); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastUpdated(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdated(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastUpdateFailed(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdateFailed(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> refresh()); } @Override public void onPlaybackStarted(int reason, int broadcastId) { } @Override public void onPlaybackStopped(int reason, int broadcastId) { } }; public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender, MediaOutputController mediaOutputController) { super(context, R.style.Theme_SystemUI_Dialog_Media); Loading @@ -114,6 +195,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements mLayoutManager = new LinearLayoutManager(mContext); mListMaxHeight = context.getResources().getDimensionPixelSize( R.dimen.media_output_dialog_list_max_height); mExecutor = Executors.newSingleThreadExecutor(); } @Override Loading Loading @@ -171,11 +253,18 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements public void onStart() { super.onStart(); mMediaOutputController.start(this); if(isBroadcastSupported()) { mMediaOutputController.registerLeBroadcastServiceCallBack(mExecutor, mBroadcastCallback); } } @Override public void onStop() { super.onStop(); if(isBroadcastSupported()) { mMediaOutputController.unregisterLeBroadcastServiceCallBack(mBroadcastCallback); } mMediaOutputController.stop(); } Loading Loading @@ -254,35 +343,12 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements mAdapter.notifyDataSetChanged(); } } // Show when remote media session is available // Show when remote media session is available or // when the device supports BT LE audio + media is playing mStopButton.setVisibility(getStopButtonVisibility()); if (isBroadcastSupported() && mMediaOutputController.isPlaying()) { mStopButton.setText(R.string.media_output_broadcast); mStopButton.setOnClickListener(v -> { SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); if (sharedPref != null && sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) { Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true"); mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView, mBroadcastSender, MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false); editor.apply(); } else { mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView, mBroadcastSender); } }); } else { mStopButton.setOnClickListener(v -> { mMediaOutputController.releaseSession(); dismiss(); }); } mStopButton.setEnabled(true); mStopButton.setText(getStopButtonText()); mStopButton.setOnClickListener(v -> onStopButtonClick()); } private Drawable resizeDrawable(Drawable drawable, int size) { Loading @@ -301,6 +367,56 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements Bitmap.createScaledBitmap(bitmap, size, size, false)); } protected void handleLeBroadcastStartFailed() { mStopButton.setText(R.string.media_output_broadcast_start_failed); mStopButton.setEnabled(false); mMainThreadHandler.postDelayed(() -> refresh(), 3000); } protected void startLeBroadcast() { mStopButton.setText(R.string.media_output_broadcast_starting); mStopButton.setEnabled(false); if (!mMediaOutputController.startBluetoothLeBroadcast()) { // If the system can't execute "broadcast start", then UI shows the error. handleLeBroadcastStartFailed(); } } protected boolean startLeBroadcastDialogForFirstTime(){ SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); if (sharedPref != null && sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) { Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true"); mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView, mBroadcastSender, MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH, (d, w) -> { startLeBroadcast(); }); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false); editor.apply(); return true; } return false; } protected void startLeBroadcastDialog() { mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView, mBroadcastSender); refresh(); } protected void stopLeBroadcast() { mStopButton.setEnabled(false); if (!mMediaOutputController.stopBluetoothLeBroadcast()) { // If the system can't execute "broadcast stop", then UI does refresh. mMainThreadHandler.post(() -> refresh()); } } abstract Drawable getAppSourceIcon(); abstract int getHeaderIconRes(); Loading @@ -315,6 +431,15 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements abstract int getStopButtonVisibility(); public CharSequence getStopButtonText() { return mContext.getText(R.string.keyboard_key_media_stop); } public void onStopButtonClick() { mMediaOutputController.releaseSession(); dismiss(); } public boolean isBroadcastSupported() { return false; } Loading packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +5 −2 Original line number Diff line number Diff line Loading @@ -142,8 +142,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { mBroadcastNotify = getDialogView().requireViewById(R.id.broadcast_info); mBroadcastNotify.setOnClickListener(v -> { mMediaOutputController.launchLeBroadcastNotifyDialog(null, null, MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON); mMediaOutputController.launchLeBroadcastNotifyDialog( /* view= */ null, /* broadcastSender= */ null, MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON, /* onClickListener= */ null); }); mBroadcastName = getDialogView().requireViewById(R.id.broadcast_name_summary); mBroadcastNameEdit = getDialogView().requireViewById(R.id.broadcast_name_edit); Loading packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +64 −17 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ package com.android.systemui.media.dialog; import static android.provider.Settings.ACTION_BLUETOOTH_PAIRING_SETTINGS; import android.annotation.CallbackExecutor; import android.app.AlertDialog; import android.app.Notification; import android.app.WallpaperColors; import android.bluetooth.BluetoothLeBroadcast; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; Loading Loading @@ -58,7 +61,7 @@ import androidx.mediarouter.media.MediaRouterParams; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.BluetoothMediaDevice; import com.android.settingslib.media.InfoMediaManager; Loading @@ -83,6 +86,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import javax.inject.Inject; Loading Loading @@ -642,17 +646,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, } void launchLeBroadcastNotifyDialog(View mediaOutputDialog, BroadcastSender broadcastSender, BroadcastNotifyDialog action) { BroadcastNotifyDialog action, final DialogInterface.OnClickListener listener) { final AlertDialog.Builder builder = new AlertDialog.Builder(mContext); switch (action) { case ACTION_FIRST_LAUNCH: builder.setTitle(R.string.media_output_first_broadcast_title); builder.setMessage(R.string.media_output_first_notify_broadcast_message); builder.setNegativeButton(android.R.string.cancel, null); builder.setPositiveButton(R.string.media_output_broadcast, (d, w) -> { launchMediaOutputBroadcastDialog(mediaOutputDialog, broadcastSender); }); builder.setPositiveButton(R.string.media_output_broadcast, listener); break; case ACTION_BROADCAST_INFO_ICON: builder.setTitle(R.string.media_output_broadcast); Loading Loading @@ -685,19 +686,65 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, || features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK)); } boolean isBluetoothLeDevice(@NonNull MediaDevice device) { if (device instanceof BluetoothMediaDevice) { final CachedBluetoothDevice cachedDevice = ((BluetoothMediaDevice) device).getCachedDevice(); boolean isConnectedLeAudioDevice = (cachedDevice != null) ? cachedDevice.isConnectedLeAudioDevice() : false; if (DEBUG) { Log.d(TAG, "isConnectedLeAudioDevice=" + isConnectedLeAudioDevice); boolean isBroadcastSupported() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); return broadcast != null ? true : false; } boolean isBluetoothLeBroadcastEnabled() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { return false; } return isConnectedLeAudioDevice; return broadcast.isEnabled(null); } boolean startBluetoothLeBroadcast() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return false; } broadcast.startBroadcast(getAppSourceName(), /*language*/ null); return true; } boolean stopBluetoothLeBroadcast() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return false; } broadcast.stopLatestBroadcast(); return true; } void registerLeBroadcastServiceCallBack( @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return; } broadcast.registerServiceCallBack(executor, callback); } void unregisterLeBroadcastServiceCallBack( @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return; } broadcast.unregisterServiceCallBack(callback); } private boolean isPlayBackInfoLocal() { return mMediaController != null Loading packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java +29 −7 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import androidx.core.graphics.drawable.IconCompat; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.settingslib.media.MediaDevice; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dagger.SysUISingleton; Loading Loading @@ -93,18 +92,41 @@ public class MediaOutputDialog extends MediaOutputBaseDialog { isActiveRemoteDevice = mMediaOutputController.isActiveRemoteDevice( mMediaOutputController.getCurrentConnectedMediaDevice()); } boolean isBroadCastSupported = isBroadcastSupported(); boolean showBroadcastButton = isBroadcastSupported() && mMediaOutputController.isPlaying(); return (isActiveRemoteDevice || isBroadCastSupported) ? View.VISIBLE : View.GONE; return (isActiveRemoteDevice || showBroadcastButton) ? View.VISIBLE : View.GONE; } @Override public boolean isBroadcastSupported() { MediaDevice device = mMediaOutputController.getCurrentConnectedMediaDevice(); if (device == null) { return false; return mMediaOutputController.isBroadcastSupported(); } @Override public CharSequence getStopButtonText() { int resId = R.string.keyboard_key_media_stop; if (isBroadcastSupported() && mMediaOutputController.isPlaying() && !mMediaOutputController.isBluetoothLeBroadcastEnabled()) { resId = R.string.media_output_broadcast; } return mContext.getText(resId); } @Override public void onStopButtonClick() { if (isBroadcastSupported() && mMediaOutputController.isPlaying()) { if (!mMediaOutputController.isBluetoothLeBroadcastEnabled()) { if (startLeBroadcastDialogForFirstTime()) { return; } startLeBroadcast(); } else { stopLeBroadcast(); } } else { mMediaOutputController.releaseSession(); dismiss(); } return mMediaOutputController.isBluetoothLeDevice(device); } @VisibleForTesting Loading Loading
packages/SystemUI/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -2283,6 +2283,10 @@ <string name="media_output_broadcast_code">Password</string> <!-- Button for change broadcast name and broadcast code [CHAR LIMIT=60] --> <string name="media_output_broadcast_dialog_save">Save</string> <!-- The "starting" text when Broadcast is starting [CHAR LIMIT=60] --> <string name="media_output_broadcast_starting">Starting…</string> <!-- The button text when Broadcast start failed [CHAR LIMIT=60] --> <string name="media_output_broadcast_start_failed">Can\u2019t broadcast</string> <!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]--> <string name="build_number_clip_data_label">Build number</string> Loading
packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +153 −28 Original line number Diff line number Diff line Loading @@ -19,7 +19,10 @@ package com.android.systemui.media.dialog; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import android.annotation.NonNull; import android.app.WallpaperColors; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; Loading Loading @@ -59,6 +62,9 @@ import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.statusbar.phone.SystemUIDialog; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * Base dialog for media output UI */ Loading @@ -69,6 +75,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private static final String EMPTY_TITLE = " "; private static final String PREF_NAME = "MediaOutputDialog"; private static final String PREF_IS_LE_BROADCAST_FIRST_LAUNCH = "PrefIsLeBroadcastFirstLaunch"; private static final boolean DEBUG = true; private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final RecyclerView.LayoutManager mLayoutManager; Loading @@ -91,6 +98,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements private Button mAppButton; private int mListMaxHeight; private WallpaperColors mWallpaperColors; private Executor mExecutor; MediaOutputBaseAdapter mAdapter; Loading @@ -103,6 +111,79 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements } }; private final BluetoothLeBroadcast.Callback mBroadcastCallback = new BluetoothLeBroadcast.Callback() { @Override public void onBroadcastStarted(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastStarted(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> startLeBroadcastDialog()); } @Override public void onBroadcastStartFailed(int reason) { if (DEBUG) { Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason); } handleLeBroadcastStartFailed(); } @Override public void onBroadcastMetadataChanged(int broadcastId, @NonNull BluetoothLeBroadcastMetadata metadata) { if (DEBUG) { Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId + ", metadata = " + metadata); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastStopped(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastStopped(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastStopFailed(int reason) { if (DEBUG) { Log.d(TAG, "onBroadcastStopFailed(), reason = " + reason); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastUpdated(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdated(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> refresh()); } @Override public void onBroadcastUpdateFailed(int reason, int broadcastId) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdateFailed(), reason = " + reason + ", broadcastId = " + broadcastId); } mMainThreadHandler.post(() -> refresh()); } @Override public void onPlaybackStarted(int reason, int broadcastId) { } @Override public void onPlaybackStopped(int reason, int broadcastId) { } }; public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender, MediaOutputController mediaOutputController) { super(context, R.style.Theme_SystemUI_Dialog_Media); Loading @@ -114,6 +195,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements mLayoutManager = new LinearLayoutManager(mContext); mListMaxHeight = context.getResources().getDimensionPixelSize( R.dimen.media_output_dialog_list_max_height); mExecutor = Executors.newSingleThreadExecutor(); } @Override Loading Loading @@ -171,11 +253,18 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements public void onStart() { super.onStart(); mMediaOutputController.start(this); if(isBroadcastSupported()) { mMediaOutputController.registerLeBroadcastServiceCallBack(mExecutor, mBroadcastCallback); } } @Override public void onStop() { super.onStop(); if(isBroadcastSupported()) { mMediaOutputController.unregisterLeBroadcastServiceCallBack(mBroadcastCallback); } mMediaOutputController.stop(); } Loading Loading @@ -254,35 +343,12 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements mAdapter.notifyDataSetChanged(); } } // Show when remote media session is available // Show when remote media session is available or // when the device supports BT LE audio + media is playing mStopButton.setVisibility(getStopButtonVisibility()); if (isBroadcastSupported() && mMediaOutputController.isPlaying()) { mStopButton.setText(R.string.media_output_broadcast); mStopButton.setOnClickListener(v -> { SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); if (sharedPref != null && sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) { Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true"); mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView, mBroadcastSender, MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false); editor.apply(); } else { mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView, mBroadcastSender); } }); } else { mStopButton.setOnClickListener(v -> { mMediaOutputController.releaseSession(); dismiss(); }); } mStopButton.setEnabled(true); mStopButton.setText(getStopButtonText()); mStopButton.setOnClickListener(v -> onStopButtonClick()); } private Drawable resizeDrawable(Drawable drawable, int size) { Loading @@ -301,6 +367,56 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements Bitmap.createScaledBitmap(bitmap, size, size, false)); } protected void handleLeBroadcastStartFailed() { mStopButton.setText(R.string.media_output_broadcast_start_failed); mStopButton.setEnabled(false); mMainThreadHandler.postDelayed(() -> refresh(), 3000); } protected void startLeBroadcast() { mStopButton.setText(R.string.media_output_broadcast_starting); mStopButton.setEnabled(false); if (!mMediaOutputController.startBluetoothLeBroadcast()) { // If the system can't execute "broadcast start", then UI shows the error. handleLeBroadcastStartFailed(); } } protected boolean startLeBroadcastDialogForFirstTime(){ SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); if (sharedPref != null && sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) { Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true"); mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView, mBroadcastSender, MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH, (d, w) -> { startLeBroadcast(); }); SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, false); editor.apply(); return true; } return false; } protected void startLeBroadcastDialog() { mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView, mBroadcastSender); refresh(); } protected void stopLeBroadcast() { mStopButton.setEnabled(false); if (!mMediaOutputController.stopBluetoothLeBroadcast()) { // If the system can't execute "broadcast stop", then UI does refresh. mMainThreadHandler.post(() -> refresh()); } } abstract Drawable getAppSourceIcon(); abstract int getHeaderIconRes(); Loading @@ -315,6 +431,15 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements abstract int getStopButtonVisibility(); public CharSequence getStopButtonText() { return mContext.getText(R.string.keyboard_key_media_stop); } public void onStopButtonClick() { mMediaOutputController.releaseSession(); dismiss(); } public boolean isBroadcastSupported() { return false; } Loading
packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +5 −2 Original line number Diff line number Diff line Loading @@ -142,8 +142,11 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { mBroadcastNotify = getDialogView().requireViewById(R.id.broadcast_info); mBroadcastNotify.setOnClickListener(v -> { mMediaOutputController.launchLeBroadcastNotifyDialog(null, null, MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON); mMediaOutputController.launchLeBroadcastNotifyDialog( /* view= */ null, /* broadcastSender= */ null, MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON, /* onClickListener= */ null); }); mBroadcastName = getDialogView().requireViewById(R.id.broadcast_name_summary); mBroadcastNameEdit = getDialogView().requireViewById(R.id.broadcast_name_edit); Loading
packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +64 −17 Original line number Diff line number Diff line Loading @@ -18,10 +18,13 @@ package com.android.systemui.media.dialog; import static android.provider.Settings.ACTION_BLUETOOTH_PAIRING_SETTINGS; import android.annotation.CallbackExecutor; import android.app.AlertDialog; import android.app.Notification; import android.app.WallpaperColors; import android.bluetooth.BluetoothLeBroadcast; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; Loading Loading @@ -58,7 +61,7 @@ import androidx.mediarouter.media.MediaRouterParams; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.BluetoothMediaDevice; import com.android.settingslib.media.InfoMediaManager; Loading @@ -83,6 +86,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import javax.inject.Inject; Loading Loading @@ -642,17 +646,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, } void launchLeBroadcastNotifyDialog(View mediaOutputDialog, BroadcastSender broadcastSender, BroadcastNotifyDialog action) { BroadcastNotifyDialog action, final DialogInterface.OnClickListener listener) { final AlertDialog.Builder builder = new AlertDialog.Builder(mContext); switch (action) { case ACTION_FIRST_LAUNCH: builder.setTitle(R.string.media_output_first_broadcast_title); builder.setMessage(R.string.media_output_first_notify_broadcast_message); builder.setNegativeButton(android.R.string.cancel, null); builder.setPositiveButton(R.string.media_output_broadcast, (d, w) -> { launchMediaOutputBroadcastDialog(mediaOutputDialog, broadcastSender); }); builder.setPositiveButton(R.string.media_output_broadcast, listener); break; case ACTION_BROADCAST_INFO_ICON: builder.setTitle(R.string.media_output_broadcast); Loading Loading @@ -685,19 +686,65 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, || features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK)); } boolean isBluetoothLeDevice(@NonNull MediaDevice device) { if (device instanceof BluetoothMediaDevice) { final CachedBluetoothDevice cachedDevice = ((BluetoothMediaDevice) device).getCachedDevice(); boolean isConnectedLeAudioDevice = (cachedDevice != null) ? cachedDevice.isConnectedLeAudioDevice() : false; if (DEBUG) { Log.d(TAG, "isConnectedLeAudioDevice=" + isConnectedLeAudioDevice); boolean isBroadcastSupported() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); return broadcast != null ? true : false; } boolean isBluetoothLeBroadcastEnabled() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { return false; } return isConnectedLeAudioDevice; return broadcast.isEnabled(null); } boolean startBluetoothLeBroadcast() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return false; } broadcast.startBroadcast(getAppSourceName(), /*language*/ null); return true; } boolean stopBluetoothLeBroadcast() { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return false; } broadcast.stopLatestBroadcast(); return true; } void registerLeBroadcastServiceCallBack( @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return; } broadcast.registerServiceCallBack(executor, callback); } void unregisterLeBroadcastServiceCallBack( @NonNull BluetoothLeBroadcast.Callback callback) { LocalBluetoothLeBroadcast broadcast = mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); if (broadcast == null) { Log.d(TAG, "The broadcast profile is null"); return; } broadcast.unregisterServiceCallBack(callback); } private boolean isPlayBackInfoLocal() { return mMediaController != null Loading
packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java +29 −7 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import androidx.core.graphics.drawable.IconCompat; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.settingslib.media.MediaDevice; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dagger.SysUISingleton; Loading Loading @@ -93,18 +92,41 @@ public class MediaOutputDialog extends MediaOutputBaseDialog { isActiveRemoteDevice = mMediaOutputController.isActiveRemoteDevice( mMediaOutputController.getCurrentConnectedMediaDevice()); } boolean isBroadCastSupported = isBroadcastSupported(); boolean showBroadcastButton = isBroadcastSupported() && mMediaOutputController.isPlaying(); return (isActiveRemoteDevice || isBroadCastSupported) ? View.VISIBLE : View.GONE; return (isActiveRemoteDevice || showBroadcastButton) ? View.VISIBLE : View.GONE; } @Override public boolean isBroadcastSupported() { MediaDevice device = mMediaOutputController.getCurrentConnectedMediaDevice(); if (device == null) { return false; return mMediaOutputController.isBroadcastSupported(); } @Override public CharSequence getStopButtonText() { int resId = R.string.keyboard_key_media_stop; if (isBroadcastSupported() && mMediaOutputController.isPlaying() && !mMediaOutputController.isBluetoothLeBroadcastEnabled()) { resId = R.string.media_output_broadcast; } return mContext.getText(resId); } @Override public void onStopButtonClick() { if (isBroadcastSupported() && mMediaOutputController.isPlaying()) { if (!mMediaOutputController.isBluetoothLeBroadcastEnabled()) { if (startLeBroadcastDialogForFirstTime()) { return; } startLeBroadcast(); } else { stopLeBroadcast(); } } else { mMediaOutputController.releaseSession(); dismiss(); } return mMediaOutputController.isBluetoothLeDevice(device); } @VisibleForTesting Loading