From 8469dea09b19da45f9cf791f51c838da46954643 Mon Sep 17 00:00:00 2001 From: timhypeng Date: Wed, 7 Oct 2020 15:19:53 +0800 Subject: [PATCH 1/6] Fix java.lang.ArrayIndexOutOfBoundsException in RemoteVolumeGroupController -Caused by removing and adding preference at the same time -Make preference operation method synchronized -Not to update preference by removing and adding. To check session status and update its content to preference -Post to UI thread to handle the onDeviceListUpdate() callback from framework Bug: 170049403 Test: make -j50 RunSettingsRoboTests Merged-In: Ibfc11e1bd99ba2e578b5d9e7dcc9132e372b68dd Change-Id: Ibfc11e1bd99ba2e578b5d9e7dcc9132e372b68dd (cherry picked from commit 1268629fda99896bda747a2531c6c3a4480d8cb1) --- .../RemoteVolumeGroupController.java | 97 +++++++++++++------ 1 file changed, 68 insertions(+), 29 deletions(-) diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java index bb62a567d58..85bb80103e0 100644 --- a/src/com/android/settings/notification/RemoteVolumeGroupController.java +++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java @@ -102,43 +102,80 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem mLocalMediaManager.stopScan(); } - private void refreshPreference() { - mPreferenceCategory.removeAll(); + private synchronized void refreshPreference() { if (!isAvailable()) { mPreferenceCategory.setVisible(false); return; } final CharSequence castVolume = mContext.getText(R.string.remote_media_volume_option_title); mPreferenceCategory.setVisible(true); - for (RoutingSessionInfo info : mRoutingSessionInfos) { - if (mPreferenceCategory.findPreference(info.getId()) != null) { - continue; + final CharSequence appName = Utils.getApplicationLabel(mContext, + info.getClientPackageName()); + RemoteVolumeSeekBarPreference seekBarPreference = mPreferenceCategory.findPreference( + info.getId()); + if (seekBarPreference != null) { + // Update slider + if (seekBarPreference.getProgress() != info.getVolume()) { + seekBarPreference.setProgress(info.getVolume()); + } + } else { + // Add slider + seekBarPreference = new RemoteVolumeSeekBarPreference(mContext); + seekBarPreference.setKey(info.getId()); + seekBarPreference.setTitle(castVolume); + seekBarPreference.setMax(info.getVolumeMax()); + seekBarPreference.setProgress(info.getVolume()); + seekBarPreference.setMin(0); + seekBarPreference.setOnPreferenceChangeListener(this); + seekBarPreference.setIcon(R.drawable.ic_volume_remote); + mPreferenceCategory.addPreference(seekBarPreference); } - final CharSequence appName = Utils.getApplicationLabel( - mContext, info.getClientPackageName()); - final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title, - appName); - // Add slider - final RemoteVolumeSeekBarPreference seekBarPreference = - new RemoteVolumeSeekBarPreference(mContext); - seekBarPreference.setKey(info.getId()); - seekBarPreference.setTitle(castVolume); - seekBarPreference.setMax(info.getVolumeMax()); - seekBarPreference.setProgress(info.getVolume()); - seekBarPreference.setMin(0); - seekBarPreference.setOnPreferenceChangeListener(this); - seekBarPreference.setIcon(R.drawable.ic_volume_remote); - mPreferenceCategory.addPreference(seekBarPreference); - // Add output indicator + + Preference switcherPreference = mPreferenceCategory.findPreference( + SWITCHER_PREFIX + info.getId()); final boolean isMediaOutputDisabled = Utils.isMediaOutputDisabled( mRouterManager, info.getClientPackageName()); - final Preference preference = new Preference(mContext); - preference.setKey(SWITCHER_PREFIX + info.getId()); - preference.setTitle(isMediaOutputDisabled ? appName : outputTitle); - preference.setSummary(info.getName()); - preference.setEnabled(!isMediaOutputDisabled); - mPreferenceCategory.addPreference(preference); + final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title, + appName); + if (switcherPreference != null) { + // Update output indicator + switcherPreference.setTitle(isMediaOutputDisabled ? appName : outputTitle); + switcherPreference.setSummary(info.getName()); + switcherPreference.setEnabled(!isMediaOutputDisabled); + } else { + // Add output indicator + switcherPreference = new Preference(mContext); + switcherPreference.setKey(SWITCHER_PREFIX + info.getId()); + switcherPreference.setTitle(isMediaOutputDisabled ? appName : outputTitle); + switcherPreference.setSummary(info.getName()); + switcherPreference.setEnabled(!isMediaOutputDisabled); + mPreferenceCategory.addPreference(switcherPreference); + } + } + + // Check and remove non-active session preference + // There is a pair of preferences for each session. First one is a seekBar preference. + // The second one shows the session information and provide an entry-point to launch output + // switcher. It is unnecessary to go through all preferences. It is fine ignore the second + // preference and only to check the seekBar's key value. + for (int i = 0; i < mPreferenceCategory.getPreferenceCount(); i = i + 2) { + final Preference preference = mPreferenceCategory.getPreference(i); + boolean isActive = false; + for (RoutingSessionInfo info : mRoutingSessionInfos) { + if (TextUtils.equals(preference.getKey(), info.getId())) { + isActive = true; + break; + } + } + if (isActive) { + continue; + } + final Preference switcherPreference = mPreferenceCategory.getPreference(i + 1); + if (switcherPreference != null) { + mPreferenceCategory.removePreference(preference); + mPreferenceCategory.removePreference(switcherPreference); + } } } @@ -181,8 +218,10 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem // Preference group is not ready. return; } - initRemoteMediaSession(); - refreshPreference(); + ThreadUtils.postOnMainThread(() -> { + initRemoteMediaSession(); + refreshPreference(); + }); } @Override From 6afe358556965e29cb1c6424da0754409ac8daff Mon Sep 17 00:00:00 2001 From: timhypeng Date: Wed, 2 Sep 2020 15:54:18 +0800 Subject: [PATCH 2/6] Add PairNewBluetoothReceiver to launch Bluetooth pairing page -A new SystemUI dialog requires to launch Bluetooth pairing page -Add receiver in manifest Bug: 155822415 Test: build pass Merged-In: I16767af3afb05eab7246be133011bc9148909d11 Change-Id: I16767af3afb05eab7246be133011bc9148909d11 --- AndroidManifest.xml | 9 ++++ .../media/BluetoothPairingReceiver.java | 46 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 src/com/android/settings/media/BluetoothPairingReceiver.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 87859abf552..0b4b75f4409 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3412,6 +3412,15 @@ android:value="com.android.settings.sound.MediaControlsSettings" /> + + + + /> + + diff --git a/src/com/android/settings/media/BluetoothPairingReceiver.java b/src/com/android/settings/media/BluetoothPairingReceiver.java new file mode 100644 index 00000000000..5b578003941 --- /dev/null +++ b/src/com/android/settings/media/BluetoothPairingReceiver.java @@ -0,0 +1,46 @@ +/* + * Copyright 2020 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. + */ + +package com.android.settings.media; + +import android.app.settings.SettingsEnums; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; + +import com.android.settings.R; +import com.android.settings.bluetooth.BluetoothPairingDetail; +import com.android.settings.core.SubSettingLauncher; +import com.android.settingslib.media.MediaOutputSliceConstants; + +/** + * BroadcastReceiver for handling media output intent + */ +public class BluetoothPairingReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (TextUtils.equals(MediaOutputSliceConstants.ACTION_LAUNCH_BLUETOOTH_PAIRING, + intent.getAction())) { + context.startActivity(new SubSettingLauncher(context) + .setDestination(BluetoothPairingDetail.class.getName()) + .setTitleRes(R.string.bluetooth_pairing_page_title) + .setSourceMetricsCategory(SettingsEnums.BLUETOOTH_PAIRING_RECEIVER) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) + .toIntent()); + } + } +} From 7127fff467a88692c9a78f44a024305eb8a3c31f Mon Sep 17 00:00:00 2001 From: timhypeng Date: Sat, 26 Sep 2020 15:43:11 +0800 Subject: [PATCH 3/6] Update OutputSwitcher from MediaOutputSlice to MediaOutputDialog in Settings -Update entry point at media indicator in volume panel -Update entry point at remote media slice in volume panel -Update entry point at remote volume group in Sound Settings -Update entry point at media output preference in Sound Settings -Hide Media output dialog when the caller is not active Bug: 155822415 Test: make -j50 RunSettingsRoboTests Merged-In: Ib6c86067522925c439f336644e4d027dbae3379c Change-Id: Ib6c86067522925c439f336644e4d027dbae3379c --- .../media/MediaOutputIndicatorSlice.java | 15 ++++++----- .../settings/media/RemoteMediaSlice.java | 25 +++++++++---------- .../RemoteVolumeGroupController.java | 17 ++++++++++--- .../android/settings/panel/VolumePanel.java | 20 ++++++++++++++- .../MediaOutputPreferenceController.java | 25 +++++++++++++++---- .../media/MediaOutputIndicatorSliceTest.java | 16 +++++++----- .../MediaOutputPreferenceControllerTest.java | 4 +-- 7 files changed, 83 insertions(+), 39 deletions(-) diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java index 305c7df1913..401a0a61a0c 100644 --- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java +++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java @@ -66,11 +66,11 @@ public class MediaOutputIndicatorSlice implements CustomSliceable { final int requestCode = TextUtils.isEmpty(getWorker().getPackageName()) ? 0 : getWorker().getPackageName().hashCode(); - final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext, - requestCode, - getMediaOutputSliceIntent(), FLAG_UPDATE_CURRENT); + final PendingIntent primaryBroadcastIntent = PendingIntent.getBroadcast(mContext, + requestCode, getMediaOutputDialogIntent(), FLAG_UPDATE_CURRENT); final SliceAction primarySliceAction = SliceAction.createDeeplink( - primaryActionIntent, icon, ListBuilder.ICON_IMAGE, title); + primaryBroadcastIntent, icon, ListBuilder.ICON_IMAGE, title); + @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext); // To set an empty icon to indent the row final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY) @@ -84,12 +84,11 @@ public class MediaOutputIndicatorSlice implements CustomSliceable { } @VisibleForTesting - Intent getMediaOutputSliceIntent() { + Intent getMediaOutputDialogIntent() { final MediaController mediaController = getWorker().getActiveLocalMediaController(); final Intent intent = new Intent() - .setPackage(Utils.SETTINGS_PACKAGE_NAME) - .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) + .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG); if (mediaController != null) { intent.putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mediaController.getSessionToken()); diff --git a/src/com/android/settings/media/RemoteMediaSlice.java b/src/com/android/settings/media/RemoteMediaSlice.java index 419826966da..1ca33b16baa 100644 --- a/src/com/android/settings/media/RemoteMediaSlice.java +++ b/src/com/android/settings/media/RemoteMediaSlice.java @@ -133,8 +133,7 @@ public class RemoteMediaSlice implements CustomSliceable { .setTitle(isMediaOutputDisabled ? spannableTitle : outputTitle) .setSubtitle(info.getName()) .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE) - .setPrimaryAction(getMediaOutputSliceAction( - info.getClientPackageName(), isMediaOutputDisabled))); + .setPrimaryAction(getMediaOutputDialogAction(info, isMediaOutputDisabled))); } return listBuilder.build(); } @@ -167,23 +166,23 @@ public class RemoteMediaSlice implements CustomSliceable { return primarySliceAction; } - private SliceAction getMediaOutputSliceAction( - String packageName, boolean isMediaOutputDisabled) { + private SliceAction getMediaOutputDialogAction(RoutingSessionInfo info, + boolean isMediaOutputDisabled) { final Intent intent = new Intent() .setAction(isMediaOutputDisabled - ? "" - : MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, packageName); + ? "" : MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, + info.getClientPackageName()); final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_volume_remote); - final int requestCode = TextUtils.isEmpty(packageName) ? 0 : packageName.hashCode(); - final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext, - requestCode, intent, 0 /* flags */); + + final PendingIntent primaryBroadcastIntent = PendingIntent.getBroadcast(mContext, + 0 /* requestCode */, intent, 0 /* flags */); final SliceAction primarySliceAction = SliceAction.createDeeplink( - primaryActionIntent, icon, ListBuilder.ICON_IMAGE, + primaryBroadcastIntent, icon, ListBuilder.ICON_IMAGE, mContext.getString(R.string.media_output_label_title, - Utils.getApplicationLabel(mContext, packageName))); + Utils.getApplicationLabel(mContext, info.getClientPackageName()))); return primarySliceAction; } diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java index bb62a567d58..4dd497f093e 100644 --- a/src/com/android/settings/notification/RemoteVolumeGroupController.java +++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java @@ -32,6 +32,7 @@ import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnDestroy; +import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaOutputSliceConstants; @@ -45,7 +46,7 @@ import java.util.List; * {@link com.android.settings.notification.RemoteVolumeSeekBarPreference} **/ public class RemoteVolumeGroupController extends BasePreferenceController implements - Preference.OnPreferenceChangeListener, LifecycleObserver, OnDestroy, + Preference.OnPreferenceChangeListener, LifecycleObserver, OnDestroy, OnPause, LocalMediaManager.DeviceCallback { private static final String KEY_REMOTE_VOLUME_GROUP = "remote_media_group"; @@ -96,6 +97,14 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem } } + @Override + public void onPause() { + // Media output dialog should not show when onPause + mContext.sendBroadcast(new Intent() + .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)); + } + @Override public void onDestroy() { mLocalMediaManager.unregisterCallback(this); @@ -159,11 +168,11 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem if (TextUtils.equals(info.getId(), preference.getKey().substring(SWITCHER_PREFIX.length()))) { final Intent intent = new Intent() - .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, info.getClientPackageName()); - mContext.startActivity(intent); + mContext.sendBroadcast(intent); return true; } } diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java index d45bfd1f5e1..7c34a7c66bc 100644 --- a/src/com/android/settings/panel/VolumePanel.java +++ b/src/com/android/settings/panel/VolumePanel.java @@ -16,6 +16,8 @@ package com.android.settings.panel; +import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; + import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI; import static com.android.settings.slices.CustomSliceRegistry.REMOTE_MEDIA_SLICE_URI; import static com.android.settings.slices.CustomSliceRegistry.VOLUME_ALARM_URI; @@ -29,12 +31,19 @@ import android.content.Intent; import android.net.Uri; import android.provider.Settings; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; + import com.android.settings.R; +import com.android.settingslib.media.MediaOutputSliceConstants; import java.util.ArrayList; import java.util.List; -public class VolumePanel implements PanelContent { +/** + * Panel data class for Volume settings. + */ +public class VolumePanel implements PanelContent, LifecycleObserver { private final Context mContext; @@ -46,6 +55,15 @@ public class VolumePanel implements PanelContent { mContext = context.getApplicationContext(); } + /** Invoked when the panel is paused. */ + @OnLifecycleEvent(ON_PAUSE) + public void onPause() { + // Media output dialog should not show when onPause + mContext.sendBroadcast(new Intent() + .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)); + } + @Override public CharSequence getTitle() { return mContext.getText(R.string.sound_settings); diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java index da92b2be424..914a9de0d27 100644 --- a/src/com/android/settings/sound/MediaOutputPreferenceController.java +++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java @@ -33,6 +33,8 @@ import com.android.settings.R; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.HearingAidProfile; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.media.MediaOutputSliceConstants; import java.util.List; @@ -45,7 +47,8 @@ import java.util.List; * - Media stream captured by remote device * - During a call. */ -public class MediaOutputPreferenceController extends AudioSwitchPreferenceController { +public class MediaOutputPreferenceController extends AudioSwitchPreferenceController + implements LifecycleObserver, OnStop { private MediaController mMediaController; @@ -63,6 +66,15 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro } } + @Override + public void onStop() { + super.onStop(); + // Media output dialog should not show when onStop + mContext.sendBroadcast(new Intent() + .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)); + } + @Override public void updateState(Preference preference) { if (preference == null) { @@ -133,10 +145,13 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro @Override public boolean handlePreferenceTreeClick(Preference preference) { if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { - final Intent intent = new Intent() - .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); + mContext.sendBroadcast(new Intent() + .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, + mMediaController.getPackageName()) + .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, + mMediaController.getSessionToken())); return true; } return false; diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java index 28620e97214..21ab8834619 100644 --- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java +++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java @@ -208,12 +208,14 @@ public class MediaOutputIndicatorSliceTest { when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME); doReturn(mMediaController).when(sMediaOutputIndicatorWorker) .getActiveLocalMediaController(); - final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputSliceIntent(); + final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputDialogIntent(); assertThat(TextUtils.equals(TEST_PACKAGE_NAME, intent.getStringExtra( MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue(); - assertThat(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT).isEqualTo(intent.getAction()); - assertThat(TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, intent.getPackage())).isTrue(); + assertThat(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG).isEqualTo( + intent.getAction()); + assertThat(TextUtils.equals(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME, + intent.getPackage())).isTrue(); assertThat(mToken == intent.getExtras().getParcelable( MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN)).isTrue(); } @@ -222,12 +224,14 @@ public class MediaOutputIndicatorSliceTest { public void getMediaOutputSliceIntent_withoutActiveLocalMedia_verifyIntentExtra() { doReturn(mMediaController).when(sMediaOutputIndicatorWorker) .getActiveLocalMediaController(); - final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputSliceIntent(); + final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputDialogIntent(); assertThat(TextUtils.isEmpty(intent.getStringExtra( MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue(); - assertThat(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT).isEqualTo(intent.getAction()); - assertThat(TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, intent.getPackage())).isTrue(); + assertThat(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG).isEqualTo( + intent.getAction()); + assertThat(TextUtils.equals(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME, + intent.getPackage())).isTrue(); assertThat(intent.getExtras().getParcelable( MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN) == null).isTrue(); } diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java index 49928dba0fd..9bee0a1fadd 100644 --- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java @@ -299,9 +299,9 @@ public class MediaOutputPreferenceControllerTest { mPreference.setKey(TEST_KEY); mController.handlePreferenceTreeClick(mPreference); - verify(mContext).startActivity(intentCaptor.capture()); + verify(mContext).sendBroadcast(intentCaptor.capture()); assertThat(intentCaptor.getValue().getAction()) - .isEqualTo(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT); + .isEqualTo(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG); } /** From 6472c98ffa36c2f7691684652fd0fbd32ff6d88b Mon Sep 17 00:00:00 2001 From: timhypeng Date: Tue, 6 Oct 2020 12:12:53 +0800 Subject: [PATCH 4/6] Update rule of launching media output dialog -Do not hide Media Output Dialog in Settings, and let dialog handles -Hide Media output slice panel when launching dialog Bug: 155822415 Test: make -j50 RunSettingsRoboTests Merged-In: I16732f625f100b259d6e53c85db40af0ec1652c5 Change-Id: I16732f625f100b259d6e53c85db40af0ec1652c5 --- .../media/MediaOutputIndicatorSlice.java | 51 +++++++++---------- .../settings/media/RemoteMediaSlice.java | 38 ++++++++++---- .../RemoteVolumeGroupController.java | 11 +--- .../android/settings/panel/VolumePanel.java | 32 ++++++++++-- .../MediaOutputPreferenceController.java | 14 +---- .../media/MediaOutputIndicatorSliceTest.java | 21 ++++++-- 6 files changed, 99 insertions(+), 68 deletions(-) diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java index 401a0a61a0c..40ee05bc01b 100644 --- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java +++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java @@ -16,18 +16,15 @@ package com.android.settings.media; -import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; - import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI; import android.annotation.ColorInt; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.media.session.MediaController; import android.net.Uri; -import android.text.TextUtils; +import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.core.graphics.drawable.IconCompat; @@ -63,13 +60,8 @@ public class MediaOutputIndicatorSlice implements CustomSliceable { com.android.internal.R.drawable.ic_settings_bluetooth); final CharSequence title = mContext.getString(R.string.media_output_label_title, Utils.getApplicationLabel(mContext, getWorker().getPackageName())); - final int requestCode = TextUtils.isEmpty(getWorker().getPackageName()) - ? 0 - : getWorker().getPackageName().hashCode(); - final PendingIntent primaryBroadcastIntent = PendingIntent.getBroadcast(mContext, - requestCode, getMediaOutputDialogIntent(), FLAG_UPDATE_CURRENT); - final SliceAction primarySliceAction = SliceAction.createDeeplink( - primaryBroadcastIntent, icon, ListBuilder.ICON_IMAGE, title); + final SliceAction primarySliceAction = SliceAction.create( + getBroadcastIntent(mContext), icon, ListBuilder.ICON_IMAGE, title); @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext); // To set an empty icon to indent the row @@ -83,21 +75,6 @@ public class MediaOutputIndicatorSlice implements CustomSliceable { return listBuilder.build(); } - @VisibleForTesting - Intent getMediaOutputDialogIntent() { - final MediaController mediaController = getWorker().getActiveLocalMediaController(); - final Intent intent = new Intent() - .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) - .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG); - if (mediaController != null) { - intent.putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, - mediaController.getSessionToken()); - intent.putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, - mediaController.getPackageName()); - } - return intent; - } - private IconCompat createEmptyIcon() { final Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); return IconCompat.createWithBitmap(bitmap); @@ -140,4 +117,26 @@ public class MediaOutputIndicatorSlice implements CustomSliceable { && getWorker().getMediaDevices().size() > 0 && getWorker().getActiveLocalMediaController() != null; } + + @Override + public void onNotifyChange(Intent intent) { + final MediaController mediaController = getWorker().getActiveLocalMediaController(); + + if (mediaController == null) { + Log.d(TAG, "No active local media controller"); + return; + } + // Launch media output dialog + mContext.sendBroadcast(new Intent() + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) + .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, + mediaController.getSessionToken()) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, + mediaController.getPackageName())); + // Dismiss volume panel + mContext.sendBroadcast(new Intent() + .setPackage(MediaOutputSliceConstants.SETTINGS_PACKAGE_NAME) + .setAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL)); + } } diff --git a/src/com/android/settings/media/RemoteMediaSlice.java b/src/com/android/settings/media/RemoteMediaSlice.java index 1ca33b16baa..5e50b55e98c 100644 --- a/src/com/android/settings/media/RemoteMediaSlice.java +++ b/src/com/android/settings/media/RemoteMediaSlice.java @@ -59,6 +59,9 @@ public class RemoteMediaSlice implements CustomSliceable { private static final String TAG = "RemoteMediaSlice"; private static final String MEDIA_ID = "media_id"; + private static final String ACTION_LAUNCH_DIALOG = "action_launch_dialog"; + private static final String SESSION_INFO = "RoutingSessionInfo"; + private static final String CUSTOMIZED_ACTION = "customized_action"; private final Context mContext; @@ -77,6 +80,20 @@ public class RemoteMediaSlice implements CustomSliceable { final String id = intent.getStringExtra(MEDIA_ID); if (!TextUtils.isEmpty(id)) { getWorker().adjustSessionVolume(id, newPosition); + return; + } + if (TextUtils.equals(ACTION_LAUNCH_DIALOG, intent.getStringExtra(CUSTOMIZED_ACTION))) { + // Launch Media Output Dialog + final RoutingSessionInfo info = intent.getParcelableExtra(SESSION_INFO); + mContext.sendBroadcast(new Intent() + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) + .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, + info.getClientPackageName())); + // Dismiss volume panel + mContext.sendBroadcast(new Intent() + .setPackage(MediaOutputSliceConstants.SETTINGS_PACKAGE_NAME) + .setAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL)); } } @@ -168,19 +185,18 @@ public class RemoteMediaSlice implements CustomSliceable { private SliceAction getMediaOutputDialogAction(RoutingSessionInfo info, boolean isMediaOutputDisabled) { - final Intent intent = new Intent() - .setAction(isMediaOutputDisabled - ? "" : MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) - .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) - .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, - info.getClientPackageName()); - final IconCompat icon = IconCompat.createWithResource(mContext, - R.drawable.ic_volume_remote); - + final Intent intent = new Intent(getUri().toString()) + .setData(getUri()) + .setClass(mContext, SliceBroadcastReceiver.class) + .putExtra(CUSTOMIZED_ACTION, isMediaOutputDisabled ? "" : ACTION_LAUNCH_DIALOG) + .putExtra(SESSION_INFO, info) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); final PendingIntent primaryBroadcastIntent = PendingIntent.getBroadcast(mContext, - 0 /* requestCode */, intent, 0 /* flags */); + info.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT); final SliceAction primarySliceAction = SliceAction.createDeeplink( - primaryBroadcastIntent, icon, ListBuilder.ICON_IMAGE, + primaryBroadcastIntent, + IconCompat.createWithResource(mContext, R.drawable.ic_volume_remote), + ListBuilder.ICON_IMAGE, mContext.getString(R.string.media_output_label_title, Utils.getApplicationLabel(mContext, info.getClientPackageName()))); return primarySliceAction; diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java index 4dd497f093e..eb72c597d2e 100644 --- a/src/com/android/settings/notification/RemoteVolumeGroupController.java +++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java @@ -32,7 +32,6 @@ import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnDestroy; -import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaOutputSliceConstants; @@ -46,7 +45,7 @@ import java.util.List; * {@link com.android.settings.notification.RemoteVolumeSeekBarPreference} **/ public class RemoteVolumeGroupController extends BasePreferenceController implements - Preference.OnPreferenceChangeListener, LifecycleObserver, OnDestroy, OnPause, + Preference.OnPreferenceChangeListener, LifecycleObserver, OnDestroy, LocalMediaManager.DeviceCallback { private static final String KEY_REMOTE_VOLUME_GROUP = "remote_media_group"; @@ -97,14 +96,6 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem } } - @Override - public void onPause() { - // Media output dialog should not show when onPause - mContext.sendBroadcast(new Intent() - .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG) - .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)); - } - @Override public void onDestroy() { mLocalMediaManager.unregisterCallback(this); diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java index 7c34a7c66bc..b5e807d8fa7 100644 --- a/src/com/android/settings/panel/VolumePanel.java +++ b/src/com/android/settings/panel/VolumePanel.java @@ -17,6 +17,7 @@ package com.android.settings.panel; import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; +import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI; import static com.android.settings.slices.CustomSliceRegistry.REMOTE_MEDIA_SLICE_URI; @@ -26,8 +27,10 @@ import static com.android.settings.slices.CustomSliceRegistry.VOLUME_MEDIA_URI; import static com.android.settings.slices.CustomSliceRegistry.VOLUME_RINGER_URI; import android.app.settings.SettingsEnums; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.net.Uri; import android.provider.Settings; @@ -47,6 +50,17 @@ public class VolumePanel implements PanelContent, LifecycleObserver { private final Context mContext; + private PanelContentCallback mCallback; + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (MediaOutputSliceConstants.ACTION_CLOSE_PANEL.equals(intent.getAction())) { + mCallback.forceClose(); + } + } + }; + public static VolumePanel create(Context context) { return new VolumePanel(context); } @@ -55,13 +69,18 @@ public class VolumePanel implements PanelContent, LifecycleObserver { mContext = context.getApplicationContext(); } + /** Invoked when the panel is resumed. */ + @OnLifecycleEvent(ON_RESUME) + public void onResume() { + final IntentFilter filter = new IntentFilter(); + filter.addAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL); + mContext.registerReceiver(mReceiver, filter); + } + /** Invoked when the panel is paused. */ @OnLifecycleEvent(ON_PAUSE) public void onPause() { - // Media output dialog should not show when onPause - mContext.sendBroadcast(new Intent() - .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG) - .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)); + mContext.unregisterReceiver(mReceiver); } @Override @@ -96,4 +115,9 @@ public class VolumePanel implements PanelContent, LifecycleObserver { public int getViewType() { return PanelContent.VIEW_TYPE_SLIDER; } + + @Override + public void registerCallback(PanelContentCallback callback) { + mCallback = callback; + } } \ No newline at end of file diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java index 914a9de0d27..7c3d2b15880 100644 --- a/src/com/android/settings/sound/MediaOutputPreferenceController.java +++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java @@ -33,8 +33,6 @@ import com.android.settings.R; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.HearingAidProfile; -import com.android.settingslib.core.lifecycle.LifecycleObserver; -import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.media.MediaOutputSliceConstants; import java.util.List; @@ -47,8 +45,7 @@ import java.util.List; * - Media stream captured by remote device * - During a call. */ -public class MediaOutputPreferenceController extends AudioSwitchPreferenceController - implements LifecycleObserver, OnStop { +public class MediaOutputPreferenceController extends AudioSwitchPreferenceController { private MediaController mMediaController; @@ -66,15 +63,6 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro } } - @Override - public void onStop() { - super.onStop(); - // Media output dialog should not show when onStop - mContext.sendBroadcast(new Intent() - .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG) - .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)); - } - @Override public void updateState(Preference preference) { if (preference == null) { diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java index 21ab8834619..68848af3ab9 100644 --- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java +++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java @@ -23,6 +23,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; @@ -54,6 +56,7 @@ import com.android.settingslib.media.MediaOutputSliceConstants; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -203,12 +206,17 @@ public class MediaOutputIndicatorSliceTest { } @Test - public void getMediaOutputSliceIntent_withActiveLocalMedia_verifyIntentExtra() { + public void onNotifyChange_withActiveLocalMedia_verifyIntentExtra() { when(mMediaController.getSessionToken()).thenReturn(mToken); when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME); doReturn(mMediaController).when(sMediaOutputIndicatorWorker) .getActiveLocalMediaController(); - final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputDialogIntent(); + ArgumentCaptor argument = ArgumentCaptor.forClass(Intent.class); + + mMediaOutputIndicatorSlice.onNotifyChange(null); + verify(mContext, times(2)).sendBroadcast(argument.capture()); + List intentList = argument.getAllValues(); + Intent intent = intentList.get(0); assertThat(TextUtils.equals(TEST_PACKAGE_NAME, intent.getStringExtra( MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue(); @@ -221,10 +229,15 @@ public class MediaOutputIndicatorSliceTest { } @Test - public void getMediaOutputSliceIntent_withoutActiveLocalMedia_verifyIntentExtra() { + public void onNotifyChange_withoutActiveLocalMedia_verifyIntentExtra() { doReturn(mMediaController).when(sMediaOutputIndicatorWorker) .getActiveLocalMediaController(); - final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputDialogIntent(); + ArgumentCaptor argument = ArgumentCaptor.forClass(Intent.class); + + mMediaOutputIndicatorSlice.onNotifyChange(null); + verify(mContext, times(2)).sendBroadcast(argument.capture()); + List intentList = argument.getAllValues(); + Intent intent = intentList.get(0); assertThat(TextUtils.isEmpty(intent.getStringExtra( MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue(); From 7207584d6ce5edf6eb21a10b1614f89fc265ff0d Mon Sep 17 00:00:00 2001 From: timhypeng Date: Mon, 2 Nov 2020 12:19:31 +0800 Subject: [PATCH 5/6] Redirect to output switcher panel to the new dialog -Redirect for Cast button -Send intent when call MediaOutputPanel::create() -Return null to finish the activity Bug: 172178632 Test: make -j50 RunSettingsRoboTests Merged-In: I1038e237113f433c847aff98a45b1dd6089d80a8 Change-Id: I1038e237113f433c847aff98a45b1dd6089d80a8 --- .../android/settings/panel/MediaOutputPanel.java | 8 +++++++- src/com/android/settings/panel/PanelFragment.java | 14 ++++++++------ .../panel/PanelFeatureProviderImplTest.java | 10 ---------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/com/android/settings/panel/MediaOutputPanel.java b/src/com/android/settings/panel/MediaOutputPanel.java index 7caf7dda7e5..4bfe3ca6940 100644 --- a/src/com/android/settings/panel/MediaOutputPanel.java +++ b/src/com/android/settings/panel/MediaOutputPanel.java @@ -44,6 +44,7 @@ import com.android.settings.Utils; import com.android.settingslib.media.InfoMediaDevice; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; +import com.android.settingslib.media.MediaOutputSliceConstants; import java.util.ArrayList; import java.util.List; @@ -72,7 +73,12 @@ public class MediaOutputPanel implements PanelContent, LocalMediaManager.DeviceC private MediaController mMediaController; public static MediaOutputPanel create(Context context, String packageName) { - return new MediaOutputPanel(context, packageName); + // Redirect to new media output dialog + context.sendBroadcast(new Intent() + .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME) + .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, packageName)); + return null; } private MediaOutputPanel(Context context, String packageName) { diff --git a/src/com/android/settings/panel/PanelFragment.java b/src/com/android/settings/panel/PanelFragment.java index 6f2d59b53bc..57585eb7173 100644 --- a/src/com/android/settings/panel/PanelFragment.java +++ b/src/com/android/settings/panel/PanelFragment.java @@ -436,12 +436,14 @@ public class PanelFragment extends Fragment { if (mLayoutView != null) { mLayoutView.getViewTreeObserver().removeOnGlobalLayoutListener(mPanelLayoutListener); } - mMetricsProvider.action( - 0 /* attribution */, - SettingsEnums.PAGE_HIDE, - mPanel.getMetricsCategory(), - mPanelClosedKey, - 0 /* value */); + if (mPanel != null) { + mMetricsProvider.action( + 0 /* attribution */, + SettingsEnums.PAGE_HIDE, + mPanel.getMetricsCategory(), + mPanelClosedKey, + 0 /* value */); + } } @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java index 54f18948cb7..f924d7a01d2 100644 --- a/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java @@ -19,7 +19,6 @@ package com.android.settings.panel; import static com.android.settings.panel.SettingsPanelActivity.KEY_MEDIA_PACKAGE_NAME; import static com.android.settings.panel.SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT; -import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT; import static com.google.common.truth.Truth.assertThat; @@ -67,13 +66,4 @@ public class PanelFeatureProviderImplTest { assertThat(panel).isInstanceOf(VolumePanel.class); } - - @Test - public void getPanel_mediaOutputKey_returnsCorrectPanel() { - mBundle.putString(KEY_PANEL_TYPE_ARGUMENT, ACTION_MEDIA_OUTPUT); - - final PanelContent panel = mProvider.getPanel(mContext, mBundle); - - assertThat(panel).isInstanceOf(MediaOutputPanel.class); - } } From ea12357dfaebec45264f6c269dd28dbc5e88a498 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 4 Dec 2020 10:19:12 +0900 Subject: [PATCH 6/6] Update the Warning text about the visibility of device name. After enabling DHCP hostname option, the device name will be carried in the DHCP packets when connecting to a Wi-Fi network, which is also visible for the DHCP server (upstream AP or hotspot). Update the warning text correspondingly. Bug: 174644890 Test: m Test: manual test to verify the warning text has been updated when changing the device name.(Settings > About Phone > Device name). Change-Id: I031a03deb8d20fb3b3a217b0fa7d45aa1b3330d1 --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 138db6a548c..92d8e9a8ae2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11480,7 +11480,7 @@ Network details - Your device name is visible to apps on your phone. It may also be seen by other people when you connect to Bluetooth devices or set up a Wi-Fi hotspot. + Your device name is visible to apps on your phone. It may also be seen by other people when you connect to Bluetooth devices, connect to a Wi-Fi network or set up a Wi-Fi hotspot. Devices