Snap for 6462261 from 7f0f127843 to mainline-release

Change-Id: Ibbc2e672e36e43b905aea490f9909a6f11cdbd4e
This commit is contained in:
android-build-team Robot
2020-05-05 07:10:26 +00:00
32 changed files with 676 additions and 266 deletions

View File

@@ -18,28 +18,43 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingEnd="?android:attr/dialogPreferredPadding" android:paddingEnd="?android:attr/dialogPreferredPadding"
android:orientation="horizontal" android:orientation="vertical"
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:minHeight="?android:attr/listPreferredItemHeightSmall"> android:minHeight="?android:attr/listPreferredItemHeightSmall">
<TextView <LinearLayout
android:id="@+id/network_request_title_text" android:layout_width="match_parent"
android:layout_width="0dp" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:orientation="horizontal"
android:paddingLeft="24dp" android:paddingStart="24dp">
android:paddingTop="18dp"
android:layout_weight="1"
android:textSize="18sp"
android:gravity="center_vertical"
style="@style/info_label"/>
<ProgressBar <TextView
android:id="@+id/network_request_title_progress" android:id="@+id/network_request_title_text"
style="?android:attr/progressBarStyleSmallTitle" android:layout_width="0dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:paddingTop="18dp"
android:layout_gravity="center_vertical" android:layout_weight="1"
android:layout_marginStart="16dip" android:textSize="20sp"
android:minWidth="32dp" android:gravity="center_vertical"
android:text="@string/progress_scanning"/> style="@style/info_label"/>
<ProgressBar
android:id="@+id/network_request_title_progress"
style="?android:attr/progressBarStyleSmallTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:gravity="center_vertical"
android:layout_marginStart="16dip"
android:minWidth="32dp"
android:text="@string/progress_scanning"/>
</LinearLayout>
<TextView
android:id="@+id/network_request_summary_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="18dp"
android:textSize="16sp"/>
</LinearLayout> </LinearLayout>

View File

@@ -8470,7 +8470,7 @@
<string name="notification_priority_title">Priority</string> <string name="notification_priority_title">Priority</string>
<!-- [CHAR LIMIT=150] Notification Importance title: important conversation level summary --> <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level summary -->
<string name="notification_channel_summary_priority">Shows at top of conversation section and appears as a bubble.</string> <string name="notification_channel_summary_priority">Shows at top of conversation section and appears as a bubble</string>
<string name="convo_not_supported_summary"><xliff:g id="app_name" example="Android Services">%1$s</xliff:g> does not support conversation-specific settings.</string> <string name="convo_not_supported_summary"><xliff:g id="app_name" example="Android Services">%1$s</xliff:g> does not support conversation-specific settings.</string>
@@ -8491,6 +8491,9 @@
<!-- [CHAR LIMIT=100] Label for on/off toggle --> <!-- [CHAR LIMIT=100] Label for on/off toggle -->
<string name="notification_switch_label">All \"<xliff:g id="app_name" example="Android Services">%1$s</xliff:g>\" notifications</string> <string name="notification_switch_label">All \"<xliff:g id="app_name" example="Android Services">%1$s</xliff:g>\" notifications</string>
<!-- [CHAR LIMIT=100] Label for on/off toggle -->
<string name="notification_app_switch_label">All <xliff:g id="app_name" example="Android Services">%1$s</xliff:g> notifications</string>
<!-- Default Apps > Default notification assistant --> <!-- Default Apps > Default notification assistant -->
<string name="default_notification_assistant">Adaptive Notifications</string> <string name="default_notification_assistant">Adaptive Notifications</string>
@@ -11736,7 +11739,12 @@
<string name="see_less">See less</string> <string name="see_less">See less</string>
<!-- Title for Network connection request Dialog [CHAR LIMIT=60] --> <!-- Title for Network connection request Dialog [CHAR LIMIT=60] -->
<string name="network_connection_request_dialog_title">Device to use with <xliff:g id="appName" example="ThirdPartyAppName">%1$s</xliff:g></string> <string name="network_connection_request_dialog_title">Connect to device</string>
<!-- Summary for Network connection request Dialog [CHAR LIMIT=NONE] -->
<string name="network_connection_request_dialog_summary">
<xliff:g id="appName" example="ThirdPartyAppName">%1$s</xliff:g>
app wants to use a temporary Wi\u2011Fi network to connect to your device
</string>
<!-- Message for Network connection timeout Dialog [CHAR LIMIT=NONE] --> <!-- Message for Network connection timeout Dialog [CHAR LIMIT=NONE] -->
<string name="network_connection_timeout_dialog_message">No devices found. Make sure devices are turned on and available to connect.</string> <string name="network_connection_timeout_dialog_message">No devices found. Make sure devices are turned on and available to connect.</string>
<!-- OK button for Network connection timeout Dialog [CHAR LIMIT=30] --> <!-- OK button for Network connection timeout Dialog [CHAR LIMIT=30] -->
@@ -11795,6 +11803,11 @@
<!-- Summary for the top level Privacy Settings [CHAR LIMIT=NONE]--> <!-- Summary for the top level Privacy Settings [CHAR LIMIT=NONE]-->
<string name="privacy_dashboard_summary">Permissions, account activity, personal data</string> <string name="privacy_dashboard_summary">Permissions, account activity, personal data</string>
<!-- UI debug setting: show media player on quick settings title [CHAR LIMIT=60] -->
<string name="quick_settings_media_player">Media resumption</string>
<!-- UI debug setting: show media player on quick settings summary [CHAR_LIMIT=NONE] -->
<string name="quick_settings_media_player_summary">Shows and persists media player in Quick Settings. Requires reboot.</string>
<!-- Label for button in contextual card for users to remove the card [CHAR LIMIT=30] --> <!-- Label for button in contextual card for users to remove the card [CHAR LIMIT=30] -->
<string name="contextual_card_dismiss_remove">Remove</string> <string name="contextual_card_dismiss_remove">Remove</string>
<!-- Label for button in contextual card for users to keep the card [CHAR LIMIT=30] --> <!-- Label for button in contextual card for users to keep the card [CHAR LIMIT=30] -->

View File

@@ -525,6 +525,11 @@
android:title="@string/usb_audio_disable_routing" android:title="@string/usb_audio_disable_routing"
android:summary="@string/usb_audio_disable_routing_summary" /> android:summary="@string/usb_audio_disable_routing_summary" />
<SwitchPreference
android:key="quick_settings_media_player"
android:title="@string/quick_settings_media_player"
android:summary="@string/quick_settings_media_player_summary" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

View File

@@ -491,6 +491,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new DebugNonRectClipOperationsPreferenceController(context)); controllers.add(new DebugNonRectClipOperationsPreferenceController(context));
controllers.add(new ForceDarkPreferenceController(context)); controllers.add(new ForceDarkPreferenceController(context));
controllers.add(new EnableBlursPreferenceController(context)); controllers.add(new EnableBlursPreferenceController(context));
controllers.add(new QuickSettingsMediaPlayerPreferenceController(context));
controllers.add(new ForceMSAAPreferenceController(context)); controllers.add(new ForceMSAAPreferenceController(context));
controllers.add(new HardwareOverlaysPreferenceController(context)); controllers.add(new HardwareOverlaysPreferenceController(context));
controllers.add(new SimulateColorSpacePreferenceController(context)); controllers.add(new SimulateColorSpacePreferenceController(context));

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 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.development;
import android.content.Context;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
/**
* Controls whether the media player should be visible in quick settings.
*/
public class QuickSettingsMediaPlayerPreferenceController extends
DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
PreferenceControllerMixin {
private static final String PREFERENCE_KEY = "quick_settings_media_player";
@VisibleForTesting
static final String SETTING_NAME = Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS;
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
@VisibleForTesting
static final int SETTING_VALUE_OFF = 0;
public QuickSettingsMediaPlayerPreferenceController(Context context) {
super(context);
}
@Override
public String getPreferenceKey() {
return PREFERENCE_KEY;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean isEnabled = (Boolean) newValue;
Settings.Global.putInt(mContext.getContentResolver(), SETTING_NAME,
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}
@Override
public void updateState(Preference preference) {
final int mode = Settings.Global.getInt(mContext.getContentResolver(), SETTING_NAME,
SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(mode != SETTING_VALUE_OFF);
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
Settings.Global.putInt(mContext.getContentResolver(), SETTING_NAME, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(false);
}
}

View File

@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.RoutingSessionInfo;
import android.net.Uri; import android.net.Uri;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
@@ -173,6 +174,10 @@ public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
return mLocalMediaManager.getSelectedMediaDevice(); return mLocalMediaManager.getSelectedMediaDevice();
} }
void adjustSessionVolume(String sessionId, int volume) {
mLocalMediaManager.adjustSessionVolume(sessionId, volume);
}
void adjustSessionVolume(int volume) { void adjustSessionVolume(int volume) {
mLocalMediaManager.adjustSessionVolume(volume); mLocalMediaManager.adjustSessionVolume(volume);
} }
@@ -189,15 +194,14 @@ public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
return mLocalMediaManager.getSessionName(); return mLocalMediaManager.getSessionName();
} }
/** List<RoutingSessionInfo> getActiveRemoteMediaDevice() {
* Find the active MediaDevice. final List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
* for (RoutingSessionInfo info : mLocalMediaManager.getActiveMediaSession()) {
* @param type the media device type. if (!info.isSystemSession()) {
* @return MediaDevice list sessionInfos.add(info);
* }
*/ }
public List<MediaDevice> getActiveMediaDevice(@MediaDevice.MediaDeviceType int type) { return sessionInfos;
return mLocalMediaManager.getActiveMediaDevice(type);
} }
/** /**

View File

@@ -24,6 +24,7 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.media.RoutingSessionInfo;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@@ -41,7 +42,6 @@ import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settings.slices.SliceBroadcastReceiver; import com.android.settings.slices.SliceBroadcastReceiver;
import com.android.settings.slices.SliceBuilderUtils; import com.android.settings.slices.SliceBuilderUtils;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.MediaOutputSliceConstants; import com.android.settingslib.media.MediaOutputSliceConstants;
import java.util.List; import java.util.List;
@@ -67,7 +67,7 @@ public class RemoteMediaSlice implements CustomSliceable {
final int newPosition = intent.getIntExtra(EXTRA_RANGE_VALUE, -1); final int newPosition = intent.getIntExtra(EXTRA_RANGE_VALUE, -1);
final String id = intent.getStringExtra(MEDIA_ID); final String id = intent.getStringExtra(MEDIA_ID);
if (!TextUtils.isEmpty(id)) { if (!TextUtils.isEmpty(id)) {
getWorker().adjustVolume(getWorker().getMediaDeviceById(id), newPosition); getWorker().adjustSessionVolume(id, newPosition);
} }
} }
@@ -80,9 +80,8 @@ public class RemoteMediaSlice implements CustomSliceable {
return listBuilder.build(); return listBuilder.build();
} }
// Only displaying remote devices // Only displaying remote devices
final List<MediaDevice> mediaDevices = getWorker().getActiveMediaDevice( final List<RoutingSessionInfo> infos = getWorker().getActiveRemoteMediaDevice();
MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE); if (infos.isEmpty()) {
if (mediaDevices.isEmpty()) {
Log.d(TAG, "No active remote media device"); Log.d(TAG, "No active remote media device");
return listBuilder.build(); return listBuilder.build();
} }
@@ -93,27 +92,25 @@ public class RemoteMediaSlice implements CustomSliceable {
// To create an empty icon to indent the row // To create an empty icon to indent the row
final IconCompat emptyIcon = createEmptyIcon(); final IconCompat emptyIcon = createEmptyIcon();
int requestCode = 0; int requestCode = 0;
for (MediaDevice mediaDevice : mediaDevices) { for (RoutingSessionInfo info : infos) {
final int maxVolume = mediaDevice.getMaxVolume(); final int maxVolume = info.getVolumeMax();
if (maxVolume <= 0) { if (maxVolume <= 0) {
Log.d(TAG, "Unable to add Slice. " + mediaDevice.getName() + ": max volume is " Log.d(TAG, "Unable to add Slice. " + info.getName() + ": max volume is "
+ maxVolume); + maxVolume);
continue; continue;
} }
final String title = castVolume + " (" + mediaDevice.getClientAppLabel() + ")";
listBuilder.addInputRange(new InputRangeBuilder() listBuilder.addInputRange(new InputRangeBuilder()
.setTitleItem(icon, ListBuilder.ICON_IMAGE) .setTitleItem(icon, ListBuilder.ICON_IMAGE)
.setTitle(title) .setTitle(castVolume)
.setInputAction(getSliderInputAction(requestCode++, mediaDevice.getId())) .setInputAction(getSliderInputAction(requestCode++, info.getId()))
.setPrimaryAction(getSoundSettingAction(title, icon, mediaDevice.getId())) .setPrimaryAction(getSoundSettingAction(castVolume, icon, info.getId()))
.setMax(maxVolume) .setMax(maxVolume)
.setValue(mediaDevice.getCurrentVolume())); .setValue(info.getVolume()));
listBuilder.addRow(new ListBuilder.RowBuilder() listBuilder.addRow(new ListBuilder.RowBuilder()
.setTitle(outputTitle) .setTitle(outputTitle)
.setSubtitle(mediaDevice.getName()) .setSubtitle(info.getName())
.setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE) .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE)
.setPrimaryAction(getMediaOutputSliceAction( .setPrimaryAction(getMediaOutputSliceAction(info.getClientPackageName())));
mediaDevice.getClientPackageName())));
} }
return listBuilder.build(); return listBuilder.build();
} }
@@ -131,7 +128,8 @@ public class RemoteMediaSlice implements CustomSliceable {
return PendingIntent.getBroadcast(mContext, requestCode, intent, 0); return PendingIntent.getBroadcast(mContext, requestCode, intent, 0);
} }
private SliceAction getSoundSettingAction(String actionTitle, IconCompat icon, String id) { private SliceAction getSoundSettingAction(CharSequence actionTitle, IconCompat icon,
String id) {
final Uri contentUri = new Uri.Builder().appendPath(id).build(); final Uri contentUri = new Uri.Builder().appendPath(id).build();
final Intent intent = SliceBuilderUtils.buildSearchResultPageIntent(mContext, final Intent intent = SliceBuilderUtils.buildSearchResultPageIntent(mContext,
SoundSettings.class.getName(), SoundSettings.class.getName(),

View File

@@ -73,6 +73,7 @@ public abstract class ActiveSubsciptionsListener
* @param context {@code Context} of this listener * @param context {@code Context} of this listener
*/ */
public ActiveSubsciptionsListener(Looper looper, Context context) { public ActiveSubsciptionsListener(Looper looper, Context context) {
super(looper);
mLooper = looper; mLooper = looper;
mContext = context; mContext = context;

View File

@@ -72,7 +72,7 @@ public class ProxySubscriptionManager implements LifecycleObserver {
private static ProxySubscriptionManager sSingleton; private static ProxySubscriptionManager sSingleton;
private ProxySubscriptionManager(Context context) { private ProxySubscriptionManager(Context context) {
final Looper looper = Looper.getMainLooper(); final Looper looper = context.getMainLooper();
mActiveSubscriptionsListeners = mActiveSubscriptionsListeners =
new ArrayList<OnActiveSubscriptionChangedListener>(); new ArrayList<OnActiveSubscriptionChangedListener>();

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 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.network.telephony;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
abstract class AbstractMobileNetworkSettings extends RestrictedDashboardFragment {
private static final String LOG_TAG = "AbsNetworkSettings";
/**
* @param restrictionKey The restriction key to check before pin protecting
* this settings page. Pass in {@link RESTRICT_IF_OVERRIDABLE} if it should
* be protected whenever a restrictions provider is set. Pass in
* null if it should never be protected.
*/
AbstractMobileNetworkSettings(String restrictionKey) {
super(restrictionKey);
}
List<AbstractPreferenceController> getPreferenceControllersAsList() {
final List<AbstractPreferenceController> result =
new ArrayList<AbstractPreferenceController>();
getPreferenceControllers().forEach(controllers -> result.addAll(controllers));
return result;
}
TelephonyStatusControlSession setTelephonyAvailabilityStatus(
Collection<AbstractPreferenceController> listOfPrefControllers) {
return (new TelephonyStatusControlSession.Builder(listOfPrefControllers))
.build();
}
}

View File

@@ -93,6 +93,9 @@ public class ApnPreferenceController extends TelephonyBasePreferenceController i
@Override @Override
public void updateState(Preference preference) { public void updateState(Preference preference) {
super.updateState(preference); super.updateState(preference);
if (mPreference == null) {
return;
}
((RestrictedPreference) mPreference).setDisabledByAdmin( ((RestrictedPreference) mPreference).setDisabledByAdmin(
MobileNetworkUtils.isDpcApnEnforced(mContext) MobileNetworkUtils.isDpcApnEnforced(mContext)
? RestrictedLockUtilsInternal.getDeviceOwner(mContext) ? RestrictedLockUtilsInternal.getDeviceOwner(mContext)

View File

@@ -35,7 +35,6 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.SubscriptionUtil; import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.SubscriptionsChangeListener; import com.android.settings.network.SubscriptionsChangeListener;
@@ -47,8 +46,8 @@ import java.util.List;
* what mobile network subscription is used by default for some service controlled by the * what mobile network subscription is used by default for some service controlled by the
* SubscriptionManager. This can be used for services such as Calls or SMS. * SubscriptionManager. This can be used for services such as Calls or SMS.
*/ */
public abstract class DefaultSubscriptionController extends BasePreferenceController implements public abstract class DefaultSubscriptionController extends TelephonyBasePreferenceController
LifecycleObserver, Preference.OnPreferenceChangeListener, implements LifecycleObserver, Preference.OnPreferenceChangeListener,
SubscriptionsChangeListener.SubscriptionsChangeListenerClient { SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
private static final String TAG = "DefaultSubController"; private static final String TAG = "DefaultSubController";
@@ -85,7 +84,7 @@ public abstract class DefaultSubscriptionController extends BasePreferenceContro
protected abstract void setDefaultSubscription(int subscriptionId); protected abstract void setDefaultSubscription(int subscriptionId);
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus(int subId) {
final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mManager); final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mManager);
if (subs.size() > 1) { if (subs.size() > 1) {
return AVAILABLE; return AVAILABLE;

View File

@@ -20,30 +20,37 @@ import android.content.Context;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.SubscriptionUtil; import com.android.settings.network.SubscriptionUtil;
public class DisableSimFooterPreferenceController extends BasePreferenceController { /**
private int mSubId; * Shows information about disable a physical SIM.
*/
public class DisableSimFooterPreferenceController extends TelephonyBasePreferenceController {
/**
* Constructor
*/
public DisableSimFooterPreferenceController(Context context, String preferenceKey) { public DisableSimFooterPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
} }
/**
* re-init for SIM based on given subscription ID.
* @param subId is the given subscription ID
*/
public void init(int subId) { public void init(int subId) {
mSubId = subId; mSubId = subId;
} }
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus(int subId) {
if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
return CONDITIONALLY_UNAVAILABLE; return CONDITIONALLY_UNAVAILABLE;
} }
SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class); SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class);
for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) { for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) {
if (info.getSubscriptionId() == mSubId) { if (info.getSubscriptionId() == subId) {
if (info.isEmbedded() || SubscriptionUtil.showToggleForPhysicalSim(subManager)) { if (info.isEmbedded() || SubscriptionUtil.showToggleForPhysicalSim(subManager)) {
return CONDITIONALLY_UNAVAILABLE; return CONDITIONALLY_UNAVAILABLE;
} }

View File

@@ -61,19 +61,6 @@ public class EnabledNetworkModePreferenceController extends
public EnabledNetworkModePreferenceController(Context context, String key) { public EnabledNetworkModePreferenceController(Context context, String key) {
super(context, key); super(context, key);
mPreferredNetworkModeObserver = new PreferredNetworkModeContentObserver(
new Handler(Looper.getMainLooper()));
mPreferredNetworkModeObserver.setPreferredNetworkModeChangedListener(
() -> updatePreference());
}
private void updatePreference() {
if (mPreferenceScreen != null) {
displayPreference(mPreferenceScreen);
}
if (mPreference != null) {
updateState(mPreference);
}
} }
@Override @Override
@@ -100,11 +87,17 @@ public class EnabledNetworkModePreferenceController extends
@OnLifecycleEvent(ON_START) @OnLifecycleEvent(ON_START)
public void onStart() { public void onStart() {
if (mPreferredNetworkModeObserver == null) {
return;
}
mPreferredNetworkModeObserver.register(mContext, mSubId); mPreferredNetworkModeObserver.register(mContext, mSubId);
} }
@OnLifecycleEvent(ON_STOP) @OnLifecycleEvent(ON_STOP)
public void onStop() { public void onStop() {
if (mPreferredNetworkModeObserver == null) {
return;
}
mPreferredNetworkModeObserver.unregister(mContext); mPreferredNetworkModeObserver.unregister(mContext);
} }
@@ -151,9 +144,25 @@ public class EnabledNetworkModePreferenceController extends
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
mBuilder = new PreferenceEntriesBuilder(mContext, mSubId); mBuilder = new PreferenceEntriesBuilder(mContext, mSubId);
if (mPreferredNetworkModeObserver == null) {
mPreferredNetworkModeObserver = new PreferredNetworkModeContentObserver(
new Handler(Looper.getMainLooper()));
mPreferredNetworkModeObserver.setPreferredNetworkModeChangedListener(
() -> updatePreference());
}
lifecycle.addObserver(this); lifecycle.addObserver(this);
} }
private void updatePreference() {
if (mPreferenceScreen != null) {
displayPreference(mPreferenceScreen);
}
if (mPreference != null) {
updateState(mPreference);
}
}
private final static class PreferenceEntriesBuilder { private final static class PreferenceEntriesBuilder {
private CarrierConfigManager mCarrierConfigManager; private CarrierConfigManager mCarrierConfigManager;
private Context mContext; private Context mContext;

View File

@@ -69,10 +69,13 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
public Enhanced4gBasePreferenceController(Context context, String key) { public Enhanced4gBasePreferenceController(Context context, String key) {
super(context, key); super(context, key);
m4gLteListeners = new ArrayList<>(); m4gLteListeners = new ArrayList<>();
mPhoneStateListener = new PhoneCallStateListener();
} }
public Enhanced4gBasePreferenceController init(int subId) { public Enhanced4gBasePreferenceController init(int subId) {
if (mPhoneStateListener == null) {
mPhoneStateListener = new PhoneCallStateListener();
}
if (mSubId == subId) { if (mSubId == subId) {
return this; return this;
} }
@@ -122,11 +125,17 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
@Override @Override
public void onStart() { public void onStart() {
if (mPhoneStateListener == null) {
return;
}
mPhoneStateListener.register(mContext, mSubId); mPhoneStateListener.register(mContext, mSubId);
} }
@Override @Override
public void onStop() { public void onStop() {
if (mPhoneStateListener == null) {
return;
}
mPhoneStateListener.unregister(); mPhoneStateListener.unregister();
} }

View File

@@ -36,8 +36,6 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.datausage.BillingCyclePreferenceController; import com.android.settings.datausage.BillingCyclePreferenceController;
import com.android.settings.datausage.DataUsageSummaryPreferenceController; import com.android.settings.datausage.DataUsageSummaryPreferenceController;
import com.android.settings.network.telephony.cdma.CdmaSubscriptionPreferenceController; import com.android.settings.network.telephony.cdma.CdmaSubscriptionPreferenceController;
@@ -47,17 +45,14 @@ import com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenc
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class MobileNetworkSettings extends RestrictedDashboardFragment { public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
private static final String LOG_TAG = "NetworkSettings"; private static final String LOG_TAG = "NetworkSettings";
public static final int REQUEST_CODE_EXIT_ECM = 17; public static final int REQUEST_CODE_EXIT_ECM = 17;
@@ -133,7 +128,11 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment {
public void onAttach(Context context) { public void onAttach(Context context) {
super.onAttach(context); super.onAttach(context);
use(DataUsageSummaryPreferenceController.class).init(mSubId); final DataUsageSummaryPreferenceController dataUsageSummaryPreferenceController =
use(DataUsageSummaryPreferenceController.class);
if (dataUsageSummaryPreferenceController != null) {
dataUsageSummaryPreferenceController.init(mSubId);
}
use(CallsDefaultSubscriptionController.class).init(getLifecycle()); use(CallsDefaultSubscriptionController.class).init(getLifecycle());
use(SmsDefaultSubscriptionController.class).init(getLifecycle()); use(SmsDefaultSubscriptionController.class).init(getLifecycle());
use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId); use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId);
@@ -189,11 +188,8 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment {
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
Log.i(LOG_TAG, "onCreate:+"); Log.i(LOG_TAG, "onCreate:+");
final Collection<List<AbstractPreferenceController>> controllerLists = final TelephonyStatusControlSession session =
getPreferenceControllers(); setTelephonyAvailabilityStatus(getPreferenceControllersAsList());
final Future<Boolean> result = ThreadUtils.postOnBackgroundThread(() ->
setupAvailabilityStatus(controllerLists)
);
super.onCreate(icicle); super.onCreate(icicle);
final Context context = getContext(); final Context context = getContext();
@@ -201,46 +197,11 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment {
mTelephonyManager = context.getSystemService(TelephonyManager.class) mTelephonyManager = context.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSubId); .createForSubscriptionId(mSubId);
//check the background thread is finished then unset the status of availability. session.close();
try {
result.get();
} catch (ExecutionException | InterruptedException exception) {
Log.e(LOG_TAG, "onCreate, setup availability status failed!", exception);
}
unsetAvailabilityStatus(controllerLists);
onRestoreInstance(icicle); onRestoreInstance(icicle);
} }
private Boolean setupAvailabilityStatus(
Collection<List<AbstractPreferenceController>> controllerLists) {
try {
controllerLists.stream().flatMap(Collection::stream)
.filter(controller -> controller instanceof TelephonyAvailabilityHandler)
.map(TelephonyAvailabilityHandler.class::cast)
.forEach(controller -> {
int status = ((BasePreferenceController) controller)
.getAvailabilityStatus();
controller.unsetAvailabilityStatus(true);
controller.setAvailabilityStatus(status);
});
return true;
} catch (Exception exception) {
Log.e(LOG_TAG, "Setup availability status failed!", exception);
return false;
}
}
private void unsetAvailabilityStatus(
Collection<List<AbstractPreferenceController>> controllerLists) {
controllerLists.stream().flatMap(Collection::stream)
.filter(controller -> controller instanceof TelephonyAvailabilityHandler)
.map(TelephonyAvailabilityHandler.class::cast)
.forEach(controller -> {
controller.unsetAvailabilityStatus(false);
});
}
@Override @Override
public void onExpandButtonClick() { public void onExpandButtonClick() {
final PreferenceScreen screen = getPreferenceScreen(); final PreferenceScreen screen = getPreferenceScreen();

View File

@@ -217,16 +217,13 @@ public class NetworkSelectSettings extends DashboardFragment {
switch (msg.what) { switch (msg.what) {
case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE: case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE:
final boolean isSucceed = (boolean) msg.obj; final boolean isSucceed = (boolean) msg.obj;
if (isSucceed) { stopNetworkQuery();
// Don't enable screen here. Wait until result of network re-scan. setProgressBarVisible(false);
startNetworkQuery(); getPreferenceScreen().setEnabled(true);
} else {
stopNetworkQuery(); mSelectedPreference.setSummary(isSucceed
setProgressBarVisible(false); ? R.string.network_connected
getPreferenceScreen().setEnabled(true); : R.string.network_could_not_connect);
// For failure case, only update the summary of selected item.
mSelectedPreference.setSummary(R.string.network_could_not_connect);
}
break; break;
case EVENT_NETWORK_SCAN_RESULTS: case EVENT_NETWORK_SCAN_RESULTS:
final List<CellInfo> results = (List<CellInfo>) msg.obj; final List<CellInfo> results = (List<CellInfo>) msg.obj;

View File

@@ -25,14 +25,16 @@ import android.content.Context;
public interface TelephonyAvailabilityHandler { public interface TelephonyAvailabilityHandler {
/** /**
* Set availability to preference controller. * Set availability status of preference controller to a fixed value.
* @param status is the given status. Which will be reported from
* {@link BasePreferenceController#getAvailabilityStatus()}
*/ */
public void setAvailabilityStatus(int status); void setAvailabilityStatus(int status);
/** /**
* Do not set availability, use * Do not set availability, use
* {@link MobileNetworkUtils#getAvailability(Context, int, TelephonyAvailabilityCallback)} * {@link MobileNetworkUtils#getAvailability(Context, int, TelephonyAvailabilityCallback)}
* to get the availability. * to get the availability.
*/ */
public void unsetAvailabilityStatus(boolean enable); void unsetAvailabilityStatus();
} }

View File

@@ -23,7 +23,6 @@ import android.telephony.SubscriptionManager;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
@@ -33,7 +32,7 @@ public abstract class TelephonyBasePreferenceController extends BasePreferenceCo
implements TelephonyAvailabilityCallback, TelephonyAvailabilityHandler { implements TelephonyAvailabilityCallback, TelephonyAvailabilityHandler {
protected int mSubId; protected int mSubId;
private AtomicInteger mAvailabilityStatus = new AtomicInteger(0); private AtomicInteger mAvailabilityStatus = new AtomicInteger(0);
private AtomicBoolean mUnsetAvailabilityStatus = new AtomicBoolean(false); private AtomicInteger mSetSessionCount = new AtomicInteger(0);
public TelephonyBasePreferenceController(Context context, String preferenceKey) { public TelephonyBasePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
@@ -42,7 +41,7 @@ public abstract class TelephonyBasePreferenceController extends BasePreferenceCo
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
if (!mUnsetAvailabilityStatus.get()) { if (mSetSessionCount.get() <= 0) {
mAvailabilityStatus.set(MobileNetworkUtils mAvailabilityStatus.set(MobileNetworkUtils
.getAvailability(mContext, mSubId, this::getAvailabilityStatus)); .getAvailability(mContext, mSubId, this::getAvailabilityStatus));
} }
@@ -52,11 +51,12 @@ public abstract class TelephonyBasePreferenceController extends BasePreferenceCo
@Override @Override
public void setAvailabilityStatus(int status) { public void setAvailabilityStatus(int status) {
mAvailabilityStatus.set(status); mAvailabilityStatus.set(status);
mSetSessionCount.getAndIncrement();
} }
@Override @Override
public void unsetAvailabilityStatus(boolean enable) { public void unsetAvailabilityStatus() {
mUnsetAvailabilityStatus.set(enable); mSetSessionCount.getAndDecrement();
} }
/** /**

View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 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.network.telephony;
import android.util.Log;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.utils.ThreadUtils;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* Session for controlling the status of TelephonyPreferenceController(s).
*
* Within this session, result of {@link BasePreferenceController#availabilityStatus()}
* would be under control.
*/
public class TelephonyStatusControlSession implements AutoCloseable {
private static final String LOG_TAG = "TelephonyStatusControlSS";
private Collection<AbstractPreferenceController> mControllers;
private Future<Boolean> mResult;
/**
* Buider of session
*/
public static class Builder {
private Collection<AbstractPreferenceController> mControllers;
/**
* Constructor
*
* @param controllers is a collection of {@link AbstractPreferenceController}
* which would have {@link BasePreferenceController#availabilityStatus()}
* under control within this session.
*/
public Builder(Collection<AbstractPreferenceController> controllers) {
mControllers = controllers;
}
/**
* Method to build this session.
* @return {@link TelephonyStatusControlSession} session been setup.
*/
public TelephonyStatusControlSession build() {
return new TelephonyStatusControlSession(mControllers);
}
}
private TelephonyStatusControlSession(Collection<AbstractPreferenceController> controllers) {
mControllers = controllers;
mResult = ThreadUtils.postOnBackgroundThread(() ->
setupAvailabilityStatus(controllers)
);
}
/**
* Close the session.
*
* No longer control the status.
*/
public void close() {
//check the background thread is finished then unset the status of availability.
try {
mResult.get();
} catch (ExecutionException | InterruptedException exception) {
Log.e(LOG_TAG, "setup availability status failed!", exception);
}
unsetAvailabilityStatus(mControllers);
}
private Boolean setupAvailabilityStatus(
Collection<AbstractPreferenceController> controllerLists) {
try {
controllerLists.stream()
.filter(controller -> controller instanceof TelephonyAvailabilityHandler)
.map(TelephonyAvailabilityHandler.class::cast)
.forEach(controller -> {
int status = ((BasePreferenceController) controller)
.getAvailabilityStatus();
controller.setAvailabilityStatus(status);
});
return true;
} catch (Exception exception) {
Log.e(LOG_TAG, "Setup availability status failed!", exception);
return false;
}
}
private void unsetAvailabilityStatus(
Collection<AbstractPreferenceController> controllerLists) {
controllerLists.stream()
.filter(controller -> controller instanceof TelephonyAvailabilityHandler)
.map(TelephonyAvailabilityHandler.class::cast)
.forEach(controller -> {
controller.unsetAvailabilityStatus();
});
}
}

View File

@@ -23,7 +23,6 @@ import android.telephony.SubscriptionManager;
import com.android.settings.core.TogglePreferenceController; import com.android.settings.core.TogglePreferenceController;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
@@ -33,8 +32,7 @@ public abstract class TelephonyTogglePreferenceController extends TogglePreferen
implements TelephonyAvailabilityCallback, TelephonyAvailabilityHandler { implements TelephonyAvailabilityCallback, TelephonyAvailabilityHandler {
protected int mSubId; protected int mSubId;
private AtomicInteger mAvailabilityStatus = new AtomicInteger(0); private AtomicInteger mAvailabilityStatus = new AtomicInteger(0);
private AtomicBoolean mUnsetAvailabilityStatus = new AtomicBoolean(false); private AtomicInteger mSetSessionCount = new AtomicInteger(0);
public TelephonyTogglePreferenceController(Context context, String preferenceKey) { public TelephonyTogglePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
@@ -43,7 +41,7 @@ public abstract class TelephonyTogglePreferenceController extends TogglePreferen
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
if (!mUnsetAvailabilityStatus.get()) { if (mSetSessionCount.get() <= 0) {
mAvailabilityStatus.set(MobileNetworkUtils mAvailabilityStatus.set(MobileNetworkUtils
.getAvailability(mContext, mSubId, this::getAvailabilityStatus)); .getAvailability(mContext, mSubId, this::getAvailabilityStatus));
} }
@@ -53,11 +51,12 @@ public abstract class TelephonyTogglePreferenceController extends TogglePreferen
@Override @Override
public void setAvailabilityStatus(int status) { public void setAvailabilityStatus(int status) {
mAvailabilityStatus.set(status); mAvailabilityStatus.set(status);
mSetSessionCount.getAndIncrement();
} }
@Override @Override
public void unsetAvailabilityStatus(boolean enable) { public void unsetAvailabilityStatus() {
mUnsetAvailabilityStatus.set(enable); mSetSessionCount.getAndDecrement();
} }
/** /**

View File

@@ -18,6 +18,8 @@ package com.android.settings.notification;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.media.RoutingSessionInfo;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -51,7 +53,7 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
static final String SWITCHER_PREFIX = "OUTPUT_SWITCHER"; static final String SWITCHER_PREFIX = "OUTPUT_SWITCHER";
private PreferenceCategory mPreferenceCategory; private PreferenceCategory mPreferenceCategory;
private List<MediaDevice> mActiveRemoteMediaDevices = new ArrayList<>(); private List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
@VisibleForTesting @VisibleForTesting
LocalMediaManager mLocalMediaManager; LocalMediaManager mLocalMediaManager;
@@ -67,7 +69,7 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
if (mActiveRemoteMediaDevices.isEmpty()) { if (mRoutingSessionInfos.isEmpty()) {
return CONDITIONALLY_UNAVAILABLE; return CONDITIONALLY_UNAVAILABLE;
} }
return AVAILABLE_UNSEARCHABLE; return AVAILABLE_UNSEARCHABLE;
@@ -77,12 +79,19 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
mPreferenceCategory = screen.findPreference(getPreferenceKey()); mPreferenceCategory = screen.findPreference(getPreferenceKey());
mActiveRemoteMediaDevices.clear(); initRemoteMediaSession();
mActiveRemoteMediaDevices.addAll(mLocalMediaManager.getActiveMediaDevice(
MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE));
refreshPreference(); refreshPreference();
} }
private void initRemoteMediaSession() {
mRoutingSessionInfos.clear();
for (RoutingSessionInfo info : mLocalMediaManager.getActiveMediaSession()) {
if (!info.isSystemSession()) {
mRoutingSessionInfos.add(info);
}
}
}
/** /**
* onDestroy() * onDestroy()
* {@link androidx.lifecycle.OnLifecycleEvent} * {@link androidx.lifecycle.OnLifecycleEvent}
@@ -102,27 +111,27 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
final CharSequence outputTitle = mContext.getText(R.string.media_output_title); final CharSequence outputTitle = mContext.getText(R.string.media_output_title);
final CharSequence castVolume = mContext.getText(R.string.remote_media_volume_option_title); final CharSequence castVolume = mContext.getText(R.string.remote_media_volume_option_title);
mPreferenceCategory.setVisible(true); mPreferenceCategory.setVisible(true);
int i = 0;
for (MediaDevice device : mActiveRemoteMediaDevices) { for (RoutingSessionInfo info : mRoutingSessionInfos) {
if (mPreferenceCategory.findPreference(device.getId()) != null) { if (mPreferenceCategory.findPreference(info.getId()) != null) {
continue; continue;
} }
// Add slider // Add slider
final RemoteVolumeSeekBarPreference seekBarPreference = final RemoteVolumeSeekBarPreference seekBarPreference =
new RemoteVolumeSeekBarPreference(mContext); new RemoteVolumeSeekBarPreference(mContext);
seekBarPreference.setKey(device.getId()); seekBarPreference.setKey(info.getId());
seekBarPreference.setTitle(castVolume + " (" + device.getClientAppLabel() + ")"); seekBarPreference.setTitle(castVolume);
seekBarPreference.setMax(device.getMaxVolume()); seekBarPreference.setMax(info.getVolumeMax());
seekBarPreference.setProgress(device.getCurrentVolume()); seekBarPreference.setProgress(info.getVolume());
seekBarPreference.setMin(0); seekBarPreference.setMin(0);
seekBarPreference.setOnPreferenceChangeListener(this); seekBarPreference.setOnPreferenceChangeListener(this);
seekBarPreference.setIcon(R.drawable.ic_volume_remote); seekBarPreference.setIcon(R.drawable.ic_volume_remote);
mPreferenceCategory.addPreference(seekBarPreference); mPreferenceCategory.addPreference(seekBarPreference);
// Add output indicator // Add output indicator
final Preference preference = new Preference(mContext); final Preference preference = new Preference(mContext);
preference.setKey(SWITCHER_PREFIX + device.getId()); preference.setKey(SWITCHER_PREFIX + info.getId());
preference.setTitle(outputTitle); preference.setTitle(outputTitle);
preference.setSummary(device.getName()); preference.setSummary(info.getName());
mPreferenceCategory.addPreference(preference); mPreferenceCategory.addPreference(preference);
} }
} }
@@ -135,7 +144,7 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
return false; return false;
} }
ThreadUtils.postOnBackgroundThread(() -> { ThreadUtils.postOnBackgroundThread(() -> {
device.requestSetVolume((int) newValue); mLocalMediaManager.adjustSessionVolume(preference.getKey(), (int) newValue);
}); });
return true; return true;
} }
@@ -145,18 +154,19 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
if (!preference.getKey().startsWith(SWITCHER_PREFIX)) { if (!preference.getKey().startsWith(SWITCHER_PREFIX)) {
return false; return false;
} }
final String key = preference.getKey().substring(SWITCHER_PREFIX.length()); for (RoutingSessionInfo info : mRoutingSessionInfos) {
final MediaDevice device = mLocalMediaManager.getMediaDeviceById(key); if (TextUtils.equals(info.getId(),
if (device == null) { preference.getKey().substring(SWITCHER_PREFIX.length()))) {
return false; final Intent intent = new Intent()
.setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
info.getClientPackageName());
mContext.startActivity(intent);
return true;
}
} }
final Intent intent = new Intent() return false;
.setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
device.getClientPackageName());
mContext.startActivity(intent);
return true;
} }
@Override @Override
@@ -170,9 +180,7 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
// Preference group is not ready. // Preference group is not ready.
return; return;
} }
mActiveRemoteMediaDevices.clear(); initRemoteMediaSession();
mActiveRemoteMediaDevices.addAll(mLocalMediaManager.getActiveMediaDevice(
MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE));
refreshPreference(); refreshPreference();
} }

View File

@@ -137,7 +137,7 @@ public class BlockPreferenceController extends NotificationPreferenceController
} else { } else {
fieldContextName = mAppRow.label; fieldContextName = mAppRow.label;
} }
return mContext.getString(R.string.notification_switch_label, fieldContextName); return mContext.getString(R.string.notification_app_switch_label, fieldContextName);
} }
} }
} }

View File

@@ -23,10 +23,13 @@ import android.content.Intent;
import android.net.wifi.ScanResult; import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import java.util.List; import java.util.List;
/** /**
@@ -39,16 +42,7 @@ abstract public class NetworkRequestDialogBaseFragment extends InstrumentedDialo
final static String EXTRA_APP_NAME = "com.android.settings.wifi.extra.APP_NAME"; final static String EXTRA_APP_NAME = "com.android.settings.wifi.extra.APP_NAME";
NetworkRequestDialogActivity mActivity = null; NetworkRequestDialogActivity mActivity = null;
private String mAppName = "";
protected String getTitle() {
final Intent intent = getActivity().getIntent();
String appName = "";
if (intent != null) {
appName = intent.getStringExtra(EXTRA_APP_NAME);
}
return getString(R.string.network_connection_request_dialog_title, appName);
}
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
@@ -61,6 +55,11 @@ abstract public class NetworkRequestDialogBaseFragment extends InstrumentedDialo
if (context instanceof NetworkRequestDialogActivity) { if (context instanceof NetworkRequestDialogActivity) {
mActivity = (NetworkRequestDialogActivity) context; mActivity = (NetworkRequestDialogActivity) context;
} }
final Intent intent = getActivity().getIntent();
if (intent != null) {
mAppName = intent.getStringExtra(EXTRA_APP_NAME);
}
} }
@Override @Override
@@ -78,6 +77,14 @@ abstract public class NetworkRequestDialogBaseFragment extends InstrumentedDialo
} }
} }
protected String getTitle() {
return getString(R.string.network_connection_request_dialog_title);
}
protected String getSummary() {
return getString(R.string.network_connection_request_dialog_summary, mAppName);
}
protected void onUserSelectionCallbackRegistration( protected void onUserSelectionCallbackRegistration(
NetworkRequestUserSelectionCallback userSelectionCallback) { NetworkRequestUserSelectionCallback userSelectionCallback) {
} }

View File

@@ -86,6 +86,8 @@ public class NetworkRequestDialogFragment extends NetworkRequestDialogBaseFragme
final TextView title = customTitle.findViewById(R.id.network_request_title_text); final TextView title = customTitle.findViewById(R.id.network_request_title_text);
title.setText(getTitle()); title.setText(getTitle());
final TextView summary = customTitle.findViewById(R.id.network_request_summary_text);
summary.setText(getSummary());
final ProgressBar progressBar = customTitle.findViewById( final ProgressBar progressBar = customTitle.findViewById(
R.id.network_request_title_progress); R.id.network_request_title_progress);

View File

@@ -7,7 +7,9 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import com.android.settings.R; import com.android.settings.R;
/** /**
@@ -33,6 +35,8 @@ public class NetworkRequestSingleSsidDialogFragment extends
final View customTitle = inflater.inflate(R.layout.network_request_dialog_title, null); final View customTitle = inflater.inflate(R.layout.network_request_dialog_title, null);
final TextView title = customTitle.findViewById(R.id.network_request_title_text); final TextView title = customTitle.findViewById(R.id.network_request_title_text);
title.setText(getTitle()); title.setText(getTitle());
final TextView summary = customTitle.findViewById(R.id.network_request_summary_text);
summary.setText(getSummary());
final ProgressBar progressBar = customTitle final ProgressBar progressBar = customTitle
.findViewById(R.id.network_request_title_progress); .findViewById(R.id.network_request_title_progress);
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);

View File

@@ -49,6 +49,7 @@ import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.testutils.shadow.ShadowAccountManager; import com.android.settings.testutils.shadow.ShadowAccountManager;
import com.android.settings.testutils.shadow.ShadowContentResolver; import com.android.settings.testutils.shadow.ShadowContentResolver;
import com.android.settings.testutils.shadow.ShadowSettingsLibUtils;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
import org.junit.After; import org.junit.After;
@@ -67,7 +68,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class}) @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class,
ShadowSettingsLibUtils.class})
public class AccountPreferenceControllerTest { public class AccountPreferenceControllerTest {
@Mock(answer = RETURNS_DEEP_STUBS) @Mock(answer = RETURNS_DEEP_STUBS)
@@ -95,7 +97,7 @@ public class AccountPreferenceControllerTest {
when(mFragment.getPreferenceScreen()).thenReturn(mScreen); when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext); when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())) when(mAccountManager.getAuthenticatorTypesAsUser(anyInt()))
.thenReturn(new AuthenticatorDescription[0]); .thenReturn(new AuthenticatorDescription[0]);
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]); when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
mController = new AccountPreferenceController(mContext, mFragment, null, mAccountHelper, mController = new AccountPreferenceController(mContext, mFragment, null, mAccountHelper,
ProfileSelectFragment.ProfileType.ALL); ProfileSelectFragment.ProfileType.ALL);
@@ -341,8 +343,8 @@ public class AccountPreferenceControllerTest {
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts); when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
Account[] accountType1 = { Account[] accountType1 = {
new Account("Account11", "com.acct1"), new Account("Account11", "com.acct1"),
new Account("Account12", "com.acct1") new Account("Account12", "com.acct1")
}; };
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class))) when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1); .thenReturn(accountType1);
@@ -535,8 +537,8 @@ public class AccountPreferenceControllerTest {
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts); when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
Account[] accountType1 = { Account[] accountType1 = {
new Account("Acct11", "com.acct1"), new Account("Acct11", "com.acct1"),
new Account("Acct12", "com.acct1") new Account("Acct12", "com.acct1")
}; };
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class))) when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1); .thenReturn(accountType1);
@@ -555,7 +557,7 @@ public class AccountPreferenceControllerTest {
mController.onResume(); mController.onResume();
// remove an account // remove an account
accountType1 = new Account[] {new Account("Acct11", "com.acct1")}; accountType1 = new Account[]{new Account("Acct11", "com.acct1")};
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class))) when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1); .thenReturn(accountType1);
@@ -577,19 +579,19 @@ public class AccountPreferenceControllerTest {
Account[] accounts = {new Account("Acct1", "com.acct1")}; Account[] accounts = {new Account("Acct1", "com.acct1")};
when(mAccountManager.getAccountsAsUser(1)).thenReturn(accounts); when(mAccountManager.getAccountsAsUser(1)).thenReturn(accounts);
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class))) when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accounts); .thenReturn(accounts);
AuthenticatorDescription[] authDescs = { AuthenticatorDescription[] authDescs = {
new AuthenticatorDescription("com.acct1", "com.android.settings", new AuthenticatorDescription("com.acct1", "com.android.settings",
R.string.account_settings_title, 0 /* iconId */, 0 /* smallIconId */, R.string.account_settings_title, 0 /* iconId */, 0 /* smallIconId */,
0 /* prefId */, false /* customTokens */) 0 /* prefId */, false /* customTokens */)
}; };
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs); when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class); AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class)); when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))) when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class)))
.thenReturn(preferenceGroup); .thenReturn(preferenceGroup);
// First time resume will build the UI with no account // First time resume will build the UI with no account
mController.onResume(); mController.onResume();

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 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.development;
import static com.android.settings.development.QuickSettingsMediaPlayerPreferenceController.SETTING_NAME;
import static com.android.settings.development.QuickSettingsMediaPlayerPreferenceController.SETTING_VALUE_OFF;
import static com.android.settings.development.QuickSettingsMediaPlayerPreferenceController.SETTING_VALUE_ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class QuickSettingsMediaPlayerPreferenceControllerTest {
@Mock
private SwitchPreference mPreference;
@Mock
private PreferenceScreen mPreferenceScreen;
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
private Context mContext;
private QuickSettingsMediaPlayerPreferenceController mController;
@Before
public void setup() {
mContext = RuntimeEnvironment.application;
mController = new QuickSettingsMediaPlayerPreferenceController(mContext);
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.displayPreference(mPreferenceScreen);
}
@Test
public void onPreferenceChanged_turnOnPreference_shouldEnable() {
mController.onPreferenceChange(mPreference, true /* new value */);
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
SETTING_NAME, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_ON);
}
@Test
public void onPreferenceChanged_turnOffPreference_shouldDisable() {
mController.onPreferenceChange(mPreference, false /* new value */);
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
SETTING_NAME, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
}
@Test
public void updateState_settingEnabled_preferenceShouldBeChecked() {
Settings.Global.putInt(mContext.getContentResolver(), SETTING_NAME, SETTING_VALUE_ON);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
Settings.Global.putInt(mContext.getContentResolver(), SETTING_NAME, SETTING_VALUE_OFF);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void onDeveloperOptionsSwitchDisabled_shouldDisable() {
mController.onDeveloperOptionsSwitchDisabled();
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
SETTING_NAME, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
verify(mPreference).setEnabled(false);
verify(mPreference).setChecked(false);
}
}

View File

@@ -31,6 +31,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.MediaRoute2ProviderService; import android.media.MediaRoute2ProviderService;
import android.media.RoutingSessionInfo;
import android.net.Uri; import android.net.Uri;
import com.android.settings.testutils.shadow.ShadowAudioManager; import com.android.settings.testutils.shadow.ShadowAudioManager;
@@ -191,4 +192,21 @@ public class MediaDeviceUpdateWorkerTest {
verify(mResolver, never()).notifyChange(URI, null); verify(mResolver, never()).notifyChange(URI, null);
} }
@Test
public void getActiveRemoteMediaSession_verifyList() {
mMediaDeviceUpdateWorker.mLocalMediaManager = mock(LocalMediaManager.class);
final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
final RoutingSessionInfo remoteSessionInfo = mock(RoutingSessionInfo.class);
final RoutingSessionInfo localSessionInfo = mock(RoutingSessionInfo.class);
when(remoteSessionInfo.isSystemSession()).thenReturn(false);
when(localSessionInfo.isSystemSession()).thenReturn(true);
routingSessionInfos.add(remoteSessionInfo);
routingSessionInfos.add(localSessionInfo);
when(mMediaDeviceUpdateWorker.mLocalMediaManager.getActiveMediaSession()).thenReturn(
routingSessionInfos);
assertThat(mMediaDeviceUpdateWorker.getActiveRemoteMediaDevice()).containsExactly(
remoteSessionInfo);
}
} }

View File

@@ -24,7 +24,7 @@ import static com.android.settings.slices.CustomSliceRegistry.REMOTE_MEDIA_SLICE
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.media.RoutingSessionInfo;
import android.net.Uri; import android.net.Uri;
import androidx.slice.Slice; import androidx.slice.Slice;
@@ -43,7 +44,6 @@ import androidx.slice.widget.SliceLiveData;
import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -64,19 +64,16 @@ import java.util.List;
public class RemoteMediaSliceTest { public class RemoteMediaSliceTest {
private static final String MEDIA_ID = "media_id"; private static final String MEDIA_ID = "media_id";
private static final String TEST_PACKAGE_LABEL = "music"; private static final String TEST_SESSION_1_ID = "test_session_1_id";
private static final String TEST_DEVICE_1_ID = "test_device_1_id"; private static final String TEST_SESSION_1_NAME = "test_session_1_name";
private static final String TEST_DEVICE_1_NAME = "test_device_1_name";
private static final int TEST_VOLUME = 3; private static final int TEST_VOLUME = 3;
private static MediaDeviceUpdateWorker sMediaDeviceUpdateWorker; private static MediaDeviceUpdateWorker sMediaDeviceUpdateWorker;
@Mock @Mock
private LocalMediaManager mLocalMediaManager; private LocalMediaManager mLocalMediaManager;
@Mock
private MediaDevice mDevice;
private final List<MediaDevice> mDevices = new ArrayList<>(); private final List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
private Context mContext; private Context mContext;
private RemoteMediaSlice mRemoteMediaSlice; private RemoteMediaSlice mRemoteMediaSlice;
@@ -93,44 +90,42 @@ public class RemoteMediaSliceTest {
sMediaDeviceUpdateWorker = spy(new MediaDeviceUpdateWorker(mContext, sMediaDeviceUpdateWorker = spy(new MediaDeviceUpdateWorker(mContext,
REMOTE_MEDIA_SLICE_URI)); REMOTE_MEDIA_SLICE_URI));
sMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager; sMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager;
when(sMediaDeviceUpdateWorker.getActiveMediaDevice( final RoutingSessionInfo remoteSessionInfo = mock(RoutingSessionInfo.class);
MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE)).thenReturn(mDevices); when(remoteSessionInfo.getId()).thenReturn(TEST_SESSION_1_ID);
when(mDevice.getId()).thenReturn(TEST_DEVICE_1_ID); when(remoteSessionInfo.getName()).thenReturn(TEST_SESSION_1_NAME);
when(mDevice.getName()).thenReturn(TEST_DEVICE_1_NAME); when(remoteSessionInfo.getVolumeMax()).thenReturn(100);
when(mDevice.getMaxVolume()).thenReturn(100); when(remoteSessionInfo.getVolume()).thenReturn(10);
when(mDevice.getCurrentVolume()).thenReturn(10); when(remoteSessionInfo.isSystemSession()).thenReturn(false);
when(mDevice.getClientAppLabel()).thenReturn(TEST_PACKAGE_LABEL); mRoutingSessionInfos.add(remoteSessionInfo);
when(sMediaDeviceUpdateWorker.getActiveRemoteMediaDevice()).thenReturn(
mRoutingSessionInfos);
} }
@Test @Test
public void onNotifyChange_noId_doNothing() { public void onNotifyChange_noId_doNothing() {
mDevices.add(mDevice);
when(mLocalMediaManager.getMediaDeviceById(mDevices, TEST_DEVICE_1_ID)).thenReturn(mDevice);
sMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.putExtra(EXTRA_RANGE_VALUE, TEST_VOLUME); intent.putExtra(EXTRA_RANGE_VALUE, TEST_VOLUME);
mRemoteMediaSlice.onNotifyChange(intent); mRemoteMediaSlice.onNotifyChange(intent);
verify(mDevice, never()).requestSetVolume(anyInt()); verify(sMediaDeviceUpdateWorker, never())
.adjustSessionVolume(TEST_SESSION_1_ID, TEST_VOLUME);
} }
@Test @Test
public void onNotifyChange_verifyAdjustVolume() { public void onNotifyChange_verifyAdjustVolume() {
mDevices.add(mDevice);
when(mLocalMediaManager.getMediaDeviceById(mDevices, TEST_DEVICE_1_ID)).thenReturn(mDevice);
sMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.putExtra(MEDIA_ID, TEST_DEVICE_1_ID); intent.putExtra(MEDIA_ID, TEST_SESSION_1_ID);
intent.putExtra(EXTRA_RANGE_VALUE, TEST_VOLUME); intent.putExtra(EXTRA_RANGE_VALUE, TEST_VOLUME);
mRemoteMediaSlice.onNotifyChange(intent); mRemoteMediaSlice.onNotifyChange(intent);
verify(mDevice).requestSetVolume(TEST_VOLUME); verify(sMediaDeviceUpdateWorker).adjustSessionVolume(TEST_SESSION_1_ID, TEST_VOLUME);
} }
@Test @Test
public void getSlice_noActiveDevice_checkRowNumber() { public void getSlice_noActiveSession_checkRowNumber() {
mRoutingSessionInfos.clear();
final Slice slice = mRemoteMediaSlice.getSlice(); final Slice slice = mRemoteMediaSlice.getSlice();
final int rows = SliceQuery.findAll(slice, FORMAT_SLICE, HINT_LIST_ITEM, null).size(); final int rows = SliceQuery.findAll(slice, FORMAT_SLICE, HINT_LIST_ITEM, null).size();
@@ -138,8 +133,7 @@ public class RemoteMediaSliceTest {
} }
@Test @Test
public void getSlice_withActiveDevice_checkRowNumber() { public void getSlice_withActiveSession_checkRowNumber() {
mDevices.add(mDevice);
final Slice slice = mRemoteMediaSlice.getSlice(); final Slice slice = mRemoteMediaSlice.getSlice();
final int rows = SliceQuery.findAll(slice, FORMAT_SLICE, HINT_LIST_ITEM, null).size(); final int rows = SliceQuery.findAll(slice, FORMAT_SLICE, HINT_LIST_ITEM, null).size();
@@ -148,15 +142,13 @@ public class RemoteMediaSliceTest {
} }
@Test @Test
public void getSlice_withActiveDevice_checkTitle() { public void getSlice_withActiveSession_checkTitle() {
mDevices.add(mDevice);
final Slice slice = mRemoteMediaSlice.getSlice(); final Slice slice = mRemoteMediaSlice.getSlice();
final SliceMetadata metadata = SliceMetadata.from(mContext, slice); final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
final SliceAction primaryAction = metadata.getPrimaryAction(); final SliceAction primaryAction = metadata.getPrimaryAction();
assertThat(primaryAction.getTitle().toString()).isEqualTo(mContext.getText( assertThat(primaryAction.getTitle().toString()).isEqualTo(mContext.getText(
com.android.settings.R.string.remote_media_volume_option_title) com.android.settings.R.string.remote_media_volume_option_title));
+ " (" + TEST_PACKAGE_LABEL + ")");
} }
@Implements(SliceBackgroundWorker.class) @Implements(SliceBackgroundWorker.class)

View File

@@ -21,11 +21,13 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.media.RoutingSessionInfo;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceCategory;
@@ -36,7 +38,6 @@ import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.widget.SeekBarPreference; import com.android.settings.widget.SeekBarPreference;
import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -55,24 +56,21 @@ import java.util.List;
public class RemoteVolumeGroupControllerTest { public class RemoteVolumeGroupControllerTest {
private static final String KEY_REMOTE_VOLUME_GROUP = "remote_media_group"; private static final String KEY_REMOTE_VOLUME_GROUP = "remote_media_group";
private static final String TEST_PACKAGE_LABEL = "music"; private static final String TEST_SESSION_1_ID = "test_session_1_id";
private static final String TEST_DEVICE_1_ID = "test_device_1_id"; private static final String TEST_SESSION_1_NAME = "test_session_1_name";
private static final String TEST_DEVICE_1_NAME = "test_device_1_name";
private static final int CURRENT_VOLUME = 30; private static final int CURRENT_VOLUME = 30;
private static final int MAX_VOLUME = 100; private static final int MAX_VOLUME = 100;
@Mock @Mock
private LocalMediaManager mLocalMediaManager; private LocalMediaManager mLocalMediaManager;
@Mock @Mock
private MediaDevice mDevice;
@Mock
private PreferenceScreen mScreen; private PreferenceScreen mScreen;
@Mock @Mock
private PreferenceManager mPreferenceManager; private PreferenceManager mPreferenceManager;
@Mock @Mock
private SharedPreferences mSharedPreferences; private SharedPreferences mSharedPreferences;
private final List<MediaDevice> mDevices = new ArrayList<>(); private final List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
private Context mContext; private Context mContext;
private RemoteVolumeGroupController mController; private RemoteVolumeGroupController mController;
@@ -89,92 +87,88 @@ public class RemoteVolumeGroupControllerTest {
when(mPreferenceCategory.getPreferenceManager()).thenReturn(mPreferenceManager); when(mPreferenceCategory.getPreferenceManager()).thenReturn(mPreferenceManager);
when(mPreferenceManager.getSharedPreferences()).thenReturn(mSharedPreferences); when(mPreferenceManager.getSharedPreferences()).thenReturn(mSharedPreferences);
when(mLocalMediaManager.getActiveMediaDevice(
MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE)).thenReturn(mDevices);
when(mDevice.getId()).thenReturn(TEST_DEVICE_1_ID);
when(mDevice.getName()).thenReturn(TEST_DEVICE_1_NAME);
when(mDevice.getMaxVolume()).thenReturn(MAX_VOLUME);
when(mDevice.getCurrentVolume()).thenReturn(CURRENT_VOLUME);
when(mDevice.getClientAppLabel()).thenReturn(TEST_PACKAGE_LABEL);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn( when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(
mPreferenceCategory); mPreferenceCategory);
final RoutingSessionInfo remoteSessionInfo = mock(RoutingSessionInfo.class);
when(remoteSessionInfo.getId()).thenReturn(TEST_SESSION_1_ID);
when(remoteSessionInfo.getName()).thenReturn(TEST_SESSION_1_NAME);
when(remoteSessionInfo.getVolumeMax()).thenReturn(MAX_VOLUME);
when(remoteSessionInfo.getVolume()).thenReturn(CURRENT_VOLUME);
when(remoteSessionInfo.isSystemSession()).thenReturn(false);
mRoutingSessionInfos.add(remoteSessionInfo);
when(mLocalMediaManager.getActiveMediaSession()).thenReturn(mRoutingSessionInfos);
} }
@Test @Test
public void getAvailabilityStatus_withActiveDevice_returnAvailableUnsearchable() { public void getAvailabilityStatus_withActiveSession_returnAvailableUnsearchable() {
mDevices.add(mDevice);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
} }
@Test @Test
public void getAvailabilityStatus_noActiveDevice_returnConditionallyUnavailable() { public void getAvailabilityStatus_noActiveSession_returnConditionallyUnavailable() {
mRoutingSessionInfos.clear();
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
} }
@Test @Test
public void displayPreference_noActiveDevice_checkPreferenceCount() { public void displayPreference_noActiveSession_checkPreferenceCount() {
mRoutingSessionInfos.clear();
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0); assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0);
} }
@Test @Test
public void displayPreference_withActiveDevice_checkPreferenceCount() { public void displayPreference_withActiveSession_checkPreferenceCount() {
mDevices.add(mDevice);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(2); assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(2);
} }
@Test @Test
public void displayPreference_withActiveDevice_checkSeekBarTitle() { public void displayPreference_withActiveSession_checkSeekBarTitle() {
mDevices.add(mDevice);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
final Preference preference = mPreferenceCategory.findPreference(TEST_DEVICE_1_ID); final Preference preference = mPreferenceCategory.findPreference(TEST_SESSION_1_ID);
assertThat(preference.getTitle()).isEqualTo(mContext.getText( assertThat(preference.getTitle()).isEqualTo(mContext.getText(
R.string.remote_media_volume_option_title) + " (" + TEST_PACKAGE_LABEL + ")"); R.string.remote_media_volume_option_title));
} }
@Test @Test
public void displayPreference_withActiveDevice_checkSeekBarMaxVolume() { public void displayPreference_withActiveSession_checkSeekBarMaxVolume() {
mDevices.add(mDevice);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
final SeekBarPreference preference = mPreferenceCategory.findPreference(TEST_DEVICE_1_ID); final SeekBarPreference preference = mPreferenceCategory.findPreference(TEST_SESSION_1_ID);
assertThat(preference.getMax()).isEqualTo(MAX_VOLUME); assertThat(preference.getMax()).isEqualTo(MAX_VOLUME);
} }
@Test @Test
public void displayPreference_withActiveDevice_checkSeekBarCurrentVolume() { public void displayPreference_withActiveSession_checkSeekBarCurrentVolume() {
mDevices.add(mDevice);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
final SeekBarPreference preference = mPreferenceCategory.findPreference(TEST_DEVICE_1_ID); final SeekBarPreference preference = mPreferenceCategory.findPreference(TEST_SESSION_1_ID);
assertThat(preference.getProgress()).isEqualTo(CURRENT_VOLUME); assertThat(preference.getProgress()).isEqualTo(CURRENT_VOLUME);
} }
@Test @Test
public void displayPreference_withActiveDevice_checkSwitcherPreferenceTitle() { public void displayPreference_withActiveSession_checkSwitcherPreferenceTitle() {
mDevices.add(mDevice);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
final Preference preference = mPreferenceCategory.findPreference( final Preference preference = mPreferenceCategory.findPreference(
RemoteVolumeGroupController.SWITCHER_PREFIX + TEST_DEVICE_1_ID); RemoteVolumeGroupController.SWITCHER_PREFIX + TEST_SESSION_1_ID);
assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.media_output_title)); assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.media_output_title));
} }
@Test @Test
public void displayPreference_withActiveDevice_checkSwitcherPreferenceSummary() { public void displayPreference_withActiveSession_checkSwitcherPreferenceSummary() {
mDevices.add(mDevice);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
final Preference preference = mPreferenceCategory.findPreference( final Preference preference = mPreferenceCategory.findPreference(
RemoteVolumeGroupController.SWITCHER_PREFIX + TEST_DEVICE_1_ID); RemoteVolumeGroupController.SWITCHER_PREFIX + TEST_SESSION_1_ID);
assertThat(preference.getSummary()).isEqualTo(TEST_DEVICE_1_NAME); assertThat(preference.getSummary()).isEqualTo(TEST_SESSION_1_NAME);
} }
} }

View File

@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import com.android.settingslib.Utils; import com.android.settingslib.Utils;
@@ -29,6 +30,11 @@ import org.robolectric.annotation.Implements;
@Implements(Utils.class) @Implements(Utils.class)
public class ShadowSettingsLibUtils { public class ShadowSettingsLibUtils {
@Implementation
protected static Drawable getBadgedIcon(Context context, Drawable icon, UserHandle user) {
return new ColorDrawable(0);
}
@Implementation @Implementation
protected static Drawable getBadgedIcon(Context context, ApplicationInfo appInfo) { protected static Drawable getBadgedIcon(Context context, ApplicationInfo appInfo) {
return new ColorDrawable(0); return new ColorDrawable(0);