packages/apps/Settings
Révision | faf7a2ad78a5cc769a6c687608df6ea449c7b4fa (tree) |
---|---|
l'heure | 2020-09-25 18:04:36 |
Auteur | TreeHugger Robot <treehugger-gerrit@goog...> |
Commiter | Android (Google) Code Review |
Merge "Disable entry point of output switcher" into rvc-qpr-dev
@@ -18,6 +18,10 @@ package com.android.settings; | ||
18 | 18 | |
19 | 19 | import static android.content.Intent.EXTRA_USER; |
20 | 20 | import static android.content.Intent.EXTRA_USER_ID; |
21 | +import static android.media.MediaRoute2Info.TYPE_GROUP; | |
22 | +import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; | |
23 | +import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; | |
24 | +import static android.media.MediaRoute2Info.TYPE_UNKNOWN; | |
21 | 25 | import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; |
22 | 26 | import static android.text.format.DateUtils.FORMAT_SHOW_DATE; |
23 | 27 |
@@ -53,6 +57,8 @@ import android.graphics.drawable.Drawable; | ||
53 | 57 | import android.graphics.drawable.VectorDrawable; |
54 | 58 | import android.hardware.face.FaceManager; |
55 | 59 | import android.hardware.fingerprint.FingerprintManager; |
60 | +import android.media.MediaRoute2Info; | |
61 | +import android.media.MediaRouter2Manager; | |
56 | 62 | import android.net.ConnectivityManager; |
57 | 63 | import android.net.LinkProperties; |
58 | 64 | import android.net.Network; |
@@ -1137,4 +1143,31 @@ public final class Utils extends com.android.settingslib.Utils { | ||
1137 | 1143 | drawable.draw(canvas); |
1138 | 1144 | return roundedBitmap; |
1139 | 1145 | } |
1146 | + | |
1147 | + /** | |
1148 | + * Returns {@code true} if needed to disable media output, otherwise returns {@code false}. | |
1149 | + */ | |
1150 | + public static boolean isMediaOutputDisabled( | |
1151 | + MediaRouter2Manager router2Manager, String packageName) { | |
1152 | + boolean isMediaOutputDisabled = false; | |
1153 | + if (!TextUtils.isEmpty(packageName)) { | |
1154 | + final List<MediaRoute2Info> infos = router2Manager.getAvailableRoutes(packageName); | |
1155 | + if (infos.size() == 1) { | |
1156 | + final MediaRoute2Info info = infos.get(0); | |
1157 | + final int deviceType = info.getType(); | |
1158 | + switch (deviceType) { | |
1159 | + case TYPE_UNKNOWN: | |
1160 | + case TYPE_REMOTE_TV: | |
1161 | + case TYPE_REMOTE_SPEAKER: | |
1162 | + case TYPE_GROUP: | |
1163 | + isMediaOutputDisabled = true; | |
1164 | + break; | |
1165 | + default: | |
1166 | + isMediaOutputDisabled = false; | |
1167 | + break; | |
1168 | + } | |
1169 | + } | |
1170 | + } | |
1171 | + return isMediaOutputDisabled; | |
1172 | + } | |
1140 | 1173 | } |
@@ -17,6 +17,7 @@ | ||
17 | 17 | package com.android.settings.media; |
18 | 18 | |
19 | 19 | import static android.app.slice.Slice.EXTRA_RANGE_VALUE; |
20 | +import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; | |
20 | 21 | |
21 | 22 | import static com.android.settings.slices.CustomSliceRegistry.REMOTE_MEDIA_SLICE_URI; |
22 | 23 |
@@ -24,11 +25,15 @@ import android.app.PendingIntent; | ||
24 | 25 | import android.content.Context; |
25 | 26 | import android.content.Intent; |
26 | 27 | import android.graphics.Bitmap; |
28 | +import android.media.MediaRouter2Manager; | |
27 | 29 | import android.media.RoutingSessionInfo; |
28 | 30 | import android.net.Uri; |
31 | +import android.text.SpannableString; | |
29 | 32 | import android.text.TextUtils; |
33 | +import android.text.style.ForegroundColorSpan; | |
30 | 34 | import android.util.Log; |
31 | 35 | |
36 | +import androidx.annotation.VisibleForTesting; | |
32 | 37 | import androidx.core.graphics.drawable.IconCompat; |
33 | 38 | import androidx.slice.Slice; |
34 | 39 | import androidx.slice.builders.ListBuilder; |
@@ -59,6 +64,9 @@ public class RemoteMediaSlice implements CustomSliceable { | ||
59 | 64 | |
60 | 65 | private MediaDeviceUpdateWorker mWorker; |
61 | 66 | |
67 | + @VisibleForTesting | |
68 | + MediaRouter2Manager mRouterManager; | |
69 | + | |
62 | 70 | public RemoteMediaSlice(Context context) { |
63 | 71 | mContext = context; |
64 | 72 | } |
@@ -80,6 +88,9 @@ public class RemoteMediaSlice implements CustomSliceable { | ||
80 | 88 | Log.e(TAG, "Unable to get the slice worker."); |
81 | 89 | return listBuilder.build(); |
82 | 90 | } |
91 | + if (mRouterManager == null) { | |
92 | + mRouterManager = MediaRouter2Manager.getInstance(mContext); | |
93 | + } | |
83 | 94 | // Only displaying remote devices |
84 | 95 | final List<RoutingSessionInfo> infos = getWorker().getActiveRemoteMediaDevice(); |
85 | 96 | if (infos.isEmpty()) { |
@@ -98,8 +109,10 @@ public class RemoteMediaSlice implements CustomSliceable { | ||
98 | 109 | + maxVolume); |
99 | 110 | continue; |
100 | 111 | } |
112 | + final CharSequence appName = Utils.getApplicationLabel( | |
113 | + mContext, info.getClientPackageName()); | |
101 | 114 | final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title, |
102 | - Utils.getApplicationLabel(mContext, info.getClientPackageName())); | |
115 | + appName); | |
103 | 116 | listBuilder.addInputRange(new InputRangeBuilder() |
104 | 117 | .setTitleItem(icon, ListBuilder.ICON_IMAGE) |
105 | 118 | .setTitle(castVolume) |
@@ -107,11 +120,21 @@ public class RemoteMediaSlice implements CustomSliceable { | ||
107 | 120 | .setPrimaryAction(getSoundSettingAction(castVolume, icon, info.getId())) |
108 | 121 | .setMax(maxVolume) |
109 | 122 | .setValue(info.getVolume())); |
123 | + | |
124 | + final boolean isMediaOutputDisabled = | |
125 | + Utils.isMediaOutputDisabled(mRouterManager, info.getClientPackageName()); | |
126 | + final SpannableString spannableTitle = new SpannableString( | |
127 | + TextUtils.isEmpty(appName) ? "" : appName); | |
128 | + spannableTitle.setSpan(new ForegroundColorSpan( | |
129 | + Utils.getColorAttrDefaultColor( | |
130 | + mContext, android.R.attr.textColorSecondary)), 0, | |
131 | + spannableTitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); | |
110 | 132 | listBuilder.addRow(new ListBuilder.RowBuilder() |
111 | - .setTitle(outputTitle) | |
133 | + .setTitle(isMediaOutputDisabled ? spannableTitle : outputTitle) | |
112 | 134 | .setSubtitle(info.getName()) |
113 | 135 | .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE) |
114 | - .setPrimaryAction(getMediaOutputSliceAction(info.getClientPackageName()))); | |
136 | + .setPrimaryAction(getMediaOutputSliceAction( | |
137 | + info.getClientPackageName(), isMediaOutputDisabled))); | |
115 | 138 | } |
116 | 139 | return listBuilder.build(); |
117 | 140 | } |
@@ -144,9 +167,12 @@ public class RemoteMediaSlice implements CustomSliceable { | ||
144 | 167 | return primarySliceAction; |
145 | 168 | } |
146 | 169 | |
147 | - private SliceAction getMediaOutputSliceAction(String packageName) { | |
170 | + private SliceAction getMediaOutputSliceAction( | |
171 | + String packageName, boolean isMediaOutputDisabled) { | |
148 | 172 | final Intent intent = new Intent() |
149 | - .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) | |
173 | + .setAction(isMediaOutputDisabled | |
174 | + ? "" | |
175 | + : MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) | |
150 | 176 | .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
151 | 177 | .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, packageName); |
152 | 178 | final IconCompat icon = IconCompat.createWithResource(mContext, |
@@ -18,6 +18,7 @@ package com.android.settings.notification; | ||
18 | 18 | |
19 | 19 | import android.content.Context; |
20 | 20 | import android.content.Intent; |
21 | +import android.media.MediaRouter2Manager; | |
21 | 22 | import android.media.RoutingSessionInfo; |
22 | 23 | import android.text.TextUtils; |
23 | 24 |
@@ -57,6 +58,8 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem | ||
57 | 58 | |
58 | 59 | @VisibleForTesting |
59 | 60 | LocalMediaManager mLocalMediaManager; |
61 | + @VisibleForTesting | |
62 | + MediaRouter2Manager mRouterManager; | |
60 | 63 | |
61 | 64 | public RemoteVolumeGroupController(Context context, String preferenceKey) { |
62 | 65 | super(context, preferenceKey); |
@@ -65,6 +68,7 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem | ||
65 | 68 | mLocalMediaManager.registerCallback(this); |
66 | 69 | mLocalMediaManager.startScan(); |
67 | 70 | } |
71 | + mRouterManager = MediaRouter2Manager.getInstance(context); | |
68 | 72 | } |
69 | 73 | |
70 | 74 | @Override |
@@ -111,8 +115,10 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem | ||
111 | 115 | if (mPreferenceCategory.findPreference(info.getId()) != null) { |
112 | 116 | continue; |
113 | 117 | } |
118 | + final CharSequence appName = Utils.getApplicationLabel( | |
119 | + mContext, info.getClientPackageName()); | |
114 | 120 | final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title, |
115 | - Utils.getApplicationLabel(mContext, info.getClientPackageName())); | |
121 | + appName); | |
116 | 122 | // Add slider |
117 | 123 | final RemoteVolumeSeekBarPreference seekBarPreference = |
118 | 124 | new RemoteVolumeSeekBarPreference(mContext); |
@@ -125,10 +131,13 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem | ||
125 | 131 | seekBarPreference.setIcon(R.drawable.ic_volume_remote); |
126 | 132 | mPreferenceCategory.addPreference(seekBarPreference); |
127 | 133 | // Add output indicator |
134 | + final boolean isMediaOutputDisabled = Utils.isMediaOutputDisabled( | |
135 | + mRouterManager, info.getClientPackageName()); | |
128 | 136 | final Preference preference = new Preference(mContext); |
129 | 137 | preference.setKey(SWITCHER_PREFIX + info.getId()); |
130 | - preference.setTitle(outputTitle); | |
138 | + preference.setTitle(isMediaOutputDisabled ? appName : outputTitle); | |
131 | 139 | preference.setSummary(info.getName()); |
140 | + preference.setEnabled(!isMediaOutputDisabled); | |
132 | 141 | mPreferenceCategory.addPreference(preference); |
133 | 142 | } |
134 | 143 | } |
@@ -40,6 +40,8 @@ import android.graphics.Color; | ||
40 | 40 | import android.graphics.drawable.BitmapDrawable; |
41 | 41 | import android.graphics.drawable.ColorDrawable; |
42 | 42 | import android.graphics.drawable.VectorDrawable; |
43 | +import android.media.MediaRoute2Info; | |
44 | +import android.media.MediaRouter2Manager; | |
43 | 45 | import android.net.ConnectivityManager; |
44 | 46 | import android.net.LinkAddress; |
45 | 47 | import android.net.LinkProperties; |
@@ -299,4 +301,33 @@ public class UtilsTest { | ||
299 | 301 | |
300 | 302 | assertThat(Utils.isSettingsIntelligence(mContext)).isFalse(); |
301 | 303 | } |
304 | + | |
305 | + @Test | |
306 | + public void isMediaOutputDisabled_infosSizeEqual1_returnsTrue() { | |
307 | + final MediaRouter2Manager router2Manager = mock(MediaRouter2Manager.class); | |
308 | + final MediaRoute2Info info = mock(MediaRoute2Info.class); | |
309 | + final List<MediaRoute2Info> infos = new ArrayList<>(); | |
310 | + infos.add(info); | |
311 | + | |
312 | + when(router2Manager.getAvailableRoutes(anyString())).thenReturn(infos); | |
313 | + when(info.getType()).thenReturn(0); | |
314 | + | |
315 | + assertThat(Utils.isMediaOutputDisabled(router2Manager, "test")).isTrue(); | |
316 | + } | |
317 | + | |
318 | + @Test | |
319 | + public void isMediaOutputDisabled_infosSizeOverThan1_returnsFalse() { | |
320 | + final MediaRouter2Manager router2Manager = mock(MediaRouter2Manager.class); | |
321 | + final MediaRoute2Info info = mock(MediaRoute2Info.class); | |
322 | + final MediaRoute2Info info2 = mock(MediaRoute2Info.class); | |
323 | + final List<MediaRoute2Info> infos = new ArrayList<>(); | |
324 | + infos.add(info); | |
325 | + infos.add(info2); | |
326 | + | |
327 | + when(router2Manager.getAvailableRoutes(anyString())).thenReturn(infos); | |
328 | + when(info.getType()).thenReturn(0); | |
329 | + when(info2.getType()).thenReturn(0); | |
330 | + | |
331 | + assertThat(Utils.isMediaOutputDisabled(router2Manager, "test")).isFalse(); | |
332 | + } | |
302 | 333 | } |
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when; | ||
32 | 32 | |
33 | 33 | import android.content.Context; |
34 | 34 | import android.content.Intent; |
35 | +import android.media.MediaRouter2Manager; | |
35 | 36 | import android.media.RoutingSessionInfo; |
36 | 37 | import android.net.Uri; |
37 | 38 |
@@ -87,6 +88,7 @@ public class RemoteMediaSliceTest { | ||
87 | 88 | SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); |
88 | 89 | |
89 | 90 | mRemoteMediaSlice = new RemoteMediaSlice(mContext); |
91 | + mRemoteMediaSlice.mRouterManager = mock(MediaRouter2Manager.class); | |
90 | 92 | sMediaDeviceUpdateWorker = spy(new MediaDeviceUpdateWorker(mContext, |
91 | 93 | REMOTE_MEDIA_SLICE_URI)); |
92 | 94 | sMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager; |
@@ -30,6 +30,7 @@ import android.content.SharedPreferences; | ||
30 | 30 | import android.content.pm.ApplicationInfo; |
31 | 31 | import android.content.pm.PackageInfo; |
32 | 32 | import android.content.pm.PackageStats; |
33 | +import android.media.MediaRouter2Manager; | |
33 | 34 | import android.media.RoutingSessionInfo; |
34 | 35 | |
35 | 36 | import androidx.preference.Preference; |
@@ -94,6 +95,7 @@ public class RemoteVolumeGroupControllerTest { | ||
94 | 95 | mContext = RuntimeEnvironment.application; |
95 | 96 | mController = new RemoteVolumeGroupController(mContext, KEY_REMOTE_VOLUME_GROUP); |
96 | 97 | mController.mLocalMediaManager = mLocalMediaManager; |
98 | + mController.mRouterManager = mock(MediaRouter2Manager.class); | |
97 | 99 | mPreferenceCategory = spy(new PreferenceCategory(mContext)); |
98 | 100 | mPreferenceCategory.setKey(mController.getPreferenceKey()); |
99 | 101 |