1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.androidx.mediarouting.activities; 18 19 import static androidx.mediarouter.media.RouteListingPreference.Item.FLAG_ONGOING_SESSION; 20 import static androidx.mediarouter.media.RouteListingPreference.Item.FLAG_ONGOING_SESSION_MANAGED; 21 import static androidx.mediarouter.media.RouteListingPreference.Item.FLAG_SUGGESTED; 22 import static androidx.mediarouter.media.RouteListingPreference.Item.SUBTEXT_CUSTOM; 23 24 import android.os.Build; 25 import android.os.Bundle; 26 import android.view.LayoutInflater; 27 import android.view.Menu; 28 import android.view.MenuItem; 29 import android.view.View; 30 import android.view.ViewGroup; 31 import android.widget.ArrayAdapter; 32 import android.widget.CheckBox; 33 import android.widget.Spinner; 34 import android.widget.Switch; 35 import android.widget.TextView; 36 import android.widget.Toast; 37 38 import androidx.appcompat.app.AlertDialog; 39 import androidx.appcompat.app.AppCompatActivity; 40 import androidx.core.view.MenuItemCompat; 41 import androidx.mediarouter.app.MediaRouteActionProvider; 42 import androidx.mediarouter.media.MediaControlIntent; 43 import androidx.mediarouter.media.MediaRouteSelector; 44 import androidx.mediarouter.media.MediaRouter; 45 import androidx.mediarouter.media.RouteListingPreference; 46 import androidx.recyclerview.widget.ItemTouchHelper; 47 import androidx.recyclerview.widget.LinearLayoutManager; 48 import androidx.recyclerview.widget.RecyclerView; 49 50 import com.example.androidx.mediarouting.R; 51 import com.example.androidx.mediarouting.RoutesManager; 52 import com.example.androidx.mediarouting.RoutesManager.RouteListingPreferenceItemHolder; 53 import com.example.androidx.mediarouting.providers.SampleMediaRouteProvider; 54 import com.example.androidx.mediarouting.ui.UiUtils; 55 import com.google.android.material.floatingactionbutton.FloatingActionButton; 56 import com.google.common.collect.ImmutableList; 57 58 import org.jspecify.annotations.NonNull; 59 import org.jspecify.annotations.Nullable; 60 61 import java.util.ArrayList; 62 import java.util.HashSet; 63 import java.util.List; 64 import java.util.Objects; 65 import java.util.Set; 66 67 /** Allows the user to manage the route listing preference of this app. */ 68 public class RouteListingPreferenceActivity extends AppCompatActivity { 69 70 private RoutesManager mRoutesManager; 71 private RecyclerView mRouteListingPreferenceRecyclerView; 72 @Override onCreate(@ullable Bundle savedInstanceState)73 protected void onCreate(@Nullable Bundle savedInstanceState) { 74 super.onCreate(savedInstanceState); 75 76 if (Build.VERSION.SDK_INT < 34) { 77 Toast.makeText( 78 /* context= */ this, 79 "Route Listing Preference requires Android U+", 80 Toast.LENGTH_LONG) 81 .show(); 82 finish(); 83 return; 84 } 85 86 setContentView(R.layout.activity_route_listing_preference); 87 88 mRoutesManager = RoutesManager.getInstance(/* context= */ this); 89 90 Switch preferSystemOrderingSwitch = findViewById(R.id.prefer_system_ordering_switch); 91 preferSystemOrderingSwitch.setChecked( 92 mRoutesManager.getRouteListingSystemOrderingPreferred()); 93 preferSystemOrderingSwitch.setOnCheckedChangeListener( 94 (unusedButton, isChecked) -> { 95 mRoutesManager.setRouteListingSystemOrderingPreferred(isChecked); 96 }); 97 preferSystemOrderingSwitch.setEnabled(mRoutesManager.isRouteListingPreferenceEnabled()); 98 99 Switch enableRouteListingPreferenceSwitch = 100 findViewById(R.id.enable_route_listing_preference_switch); 101 enableRouteListingPreferenceSwitch.setChecked( 102 mRoutesManager.isRouteListingPreferenceEnabled()); 103 enableRouteListingPreferenceSwitch.setOnCheckedChangeListener( 104 (unusedButton, isChecked) -> { 105 mRoutesManager.setRouteListingPreferenceEnabled(isChecked); 106 preferSystemOrderingSwitch.setEnabled(isChecked); 107 }); 108 109 mRouteListingPreferenceRecyclerView = 110 findViewById(R.id.route_listing_preference_recycler_view); 111 new ItemTouchHelper(new RecyclerViewCallback()) 112 .attachToRecyclerView(mRouteListingPreferenceRecyclerView); 113 mRouteListingPreferenceRecyclerView.setLayoutManager( 114 new LinearLayoutManager(/* context= */ this)); 115 mRouteListingPreferenceRecyclerView.setHasFixedSize(true); 116 mRouteListingPreferenceRecyclerView.setAdapter( 117 new RouteListingPreferenceRecyclerViewAdapter()); 118 119 FloatingActionButton newRouteButton = 120 findViewById(R.id.new_route_listing_preference_item_button); 121 newRouteButton.setOnClickListener( 122 view -> 123 setUpRouteListingPreferenceItemEditionDialog( 124 mRoutesManager.getRouteListingPreferenceItems().size())); 125 } 126 127 @Override onCreateOptionsMenu(@onNull Menu menu)128 public boolean onCreateOptionsMenu(@NonNull Menu menu) { 129 super.onCreateOptionsMenu(menu); 130 getMenuInflater().inflate(R.menu.route_button_menu, menu); 131 MenuItem mediaRouteMenuItem = menu.findItem(R.id.route_button_menu_item); 132 MediaRouteActionProvider mediaRouteActionProvider = 133 (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem); 134 MediaRouteSelector routeSelector = 135 new MediaRouteSelector.Builder() 136 .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 137 .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_AUDIO_PLAYBACK) 138 .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_VIDEO_PLAYBACK) 139 .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) 140 .addControlCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE) 141 .build(); 142 Objects.requireNonNull(mediaRouteActionProvider).setRouteSelector(routeSelector); 143 return true; 144 } 145 setUpRouteListingPreferenceItemEditionDialog(int itemPositionInList)146 private void setUpRouteListingPreferenceItemEditionDialog(int itemPositionInList) { 147 List<RouteListingPreferenceItemHolder> routeListingPreference = 148 mRoutesManager.getRouteListingPreferenceItems(); 149 List<MediaRouter.RouteInfo> routesWithNoAssociatedListingPreferenceItem = 150 getRoutesWithNoAssociatedListingPreferenceItem(); 151 if (itemPositionInList == routeListingPreference.size() 152 && routesWithNoAssociatedListingPreferenceItem.isEmpty()) { 153 Toast.makeText(/* context= */ this, "No (more) routes available", Toast.LENGTH_LONG) 154 .show(); 155 return; 156 } 157 View dialogView = 158 getLayoutInflater() 159 .inflate(R.layout.route_listing_preference_item_dialog, /* root= */ null); 160 161 Spinner routeSpinner = dialogView.findViewById(R.id.rlp_item_dialog_route_name_spinner); 162 List<RouteListingPreferenceItemHolder> spinnerEntries = new ArrayList<>(); 163 164 Spinner selectionBehaviorSpinner = 165 dialogView.findViewById(R.id.rlp_item_dialog_selection_behavior_spinner); 166 UiUtils.setUpEnumBasedSpinner( 167 /* context= */ this, 168 selectionBehaviorSpinner, 169 RouteListingPreferenceItemSelectionBehavior.SELECTION_BEHAVIOR_TRANSFER, 170 (unused) -> {}); 171 172 CheckBox ongoingSessionCheckBox = 173 dialogView.findViewById(R.id.rlp_item_dialog_ongoing_session_checkbox); 174 CheckBox sessionManagedCheckBox = 175 dialogView.findViewById(R.id.rlp_item_dialog_session_managed_checkbox); 176 CheckBox suggestedRouteCheckBox = 177 dialogView.findViewById(R.id.rlp_item_dialog_suggested_checkbox); 178 179 Spinner subtextSpinner = dialogView.findViewById(R.id.rlp_item_dialog_subtext_spinner); 180 UiUtils.setUpEnumBasedSpinner( 181 /* context= */ this, 182 subtextSpinner, 183 RouteListingPreferenceItemSubtext.SUBTEXT_NONE, 184 (unused) -> {}); 185 186 if (itemPositionInList < routeListingPreference.size()) { 187 RouteListingPreferenceItemHolder itemHolder = 188 routeListingPreference.get(itemPositionInList); 189 spinnerEntries.add(itemHolder); 190 int selectionBehaviorOrdinalIndex = 191 RouteListingPreferenceItemSelectionBehavior.fromConstant( 192 itemHolder.mItem.getSelectionBehavior()) 193 .ordinal(); 194 selectionBehaviorSpinner.setSelection(selectionBehaviorOrdinalIndex); 195 ongoingSessionCheckBox.setChecked(itemHolder.hasFlag(FLAG_ONGOING_SESSION)); 196 sessionManagedCheckBox.setChecked(itemHolder.hasFlag(FLAG_ONGOING_SESSION_MANAGED)); 197 suggestedRouteCheckBox.setChecked(itemHolder.hasFlag(FLAG_SUGGESTED)); 198 int subtextOrdinalIndex = 199 RouteListingPreferenceItemSubtext.fromConstant(itemHolder.mItem.getSubText()) 200 .ordinal(); 201 subtextSpinner.setSelection(subtextOrdinalIndex); 202 } 203 for (MediaRouter.RouteInfo routeInfo : routesWithNoAssociatedListingPreferenceItem) { 204 spinnerEntries.add( 205 new RouteListingPreferenceItemHolder( 206 new RouteListingPreference.Item.Builder(routeInfo.getId()).build(), 207 routeInfo.getName())); 208 } 209 routeSpinner.setAdapter( 210 new ArrayAdapter<>( 211 /* context= */ this, android.R.layout.simple_spinner_item, spinnerEntries)); 212 213 AlertDialog editRlpItemDialog = 214 new AlertDialog.Builder(this) 215 .setView(dialogView) 216 .setPositiveButton( 217 "Accept", 218 (unusedDialog, unusedWhich) -> { 219 RouteListingPreferenceItemHolder item = 220 (RouteListingPreferenceItemHolder) 221 routeSpinner.getSelectedItem(); 222 RouteListingPreferenceItemSelectionBehavior selectionBehavior = 223 (RouteListingPreferenceItemSelectionBehavior) 224 selectionBehaviorSpinner.getSelectedItem(); 225 int flags = 0; 226 flags |= 227 ongoingSessionCheckBox.isChecked() 228 ? FLAG_ONGOING_SESSION 229 : 0; 230 flags |= 231 sessionManagedCheckBox.isChecked() 232 ? FLAG_ONGOING_SESSION_MANAGED 233 : 0; 234 flags |= 235 suggestedRouteCheckBox.isChecked() ? FLAG_SUGGESTED : 0; 236 RouteListingPreferenceItemSubtext subtext = 237 (RouteListingPreferenceItemSubtext) 238 subtextSpinner.getSelectedItem(); 239 onEditRlpItemDialogAccepted( 240 item.mItem.getRouteId(), 241 item.mRouteName, 242 selectionBehavior.mConstant, 243 flags, 244 subtext.mConstant, 245 itemPositionInList); 246 }) 247 .setNegativeButton("Dismiss", (unusedDialog, unusedWhich) -> {}) 248 .create(); 249 250 editRlpItemDialog.show(); 251 } 252 onEditRlpItemDialogAccepted( String routeId, String routeName, int selectionBehavior, int flags, int subtext, int itemPositionInList)253 private void onEditRlpItemDialogAccepted( 254 String routeId, 255 String routeName, 256 int selectionBehavior, 257 int flags, 258 int subtext, 259 int itemPositionInList) { 260 ArrayList<RouteListingPreferenceItemHolder> newRouteListingPreference = 261 new ArrayList<>(mRoutesManager.getRouteListingPreferenceItems()); 262 RecyclerView.Adapter<?> adapter = mRouteListingPreferenceRecyclerView.getAdapter(); 263 RouteListingPreference.Item.Builder newItemBuilder = 264 new RouteListingPreference.Item.Builder(routeId) 265 .setFlags(flags) 266 .setSelectionBehavior(selectionBehavior) 267 .setSubText(subtext); 268 if (subtext == SUBTEXT_CUSTOM) { 269 newItemBuilder.setCustomSubtextMessage("A custom subtext"); 270 } 271 RouteListingPreference.Item newItem = newItemBuilder.build(); 272 RouteListingPreferenceItemHolder newItemAndNamePair = 273 new RouteListingPreferenceItemHolder(newItem, routeName); 274 if (itemPositionInList < newRouteListingPreference.size()) { 275 newRouteListingPreference.set(itemPositionInList, newItemAndNamePair); 276 adapter.notifyItemChanged(itemPositionInList); 277 } else { 278 newRouteListingPreference.add(newItemAndNamePair); 279 adapter.notifyItemInserted(itemPositionInList); 280 } 281 mRoutesManager.setRouteListingPreferenceItems(newRouteListingPreference); 282 } 283 284 private @NonNull ImmutableList<MediaRouter.RouteInfo> getRoutesWithNoAssociatedListingPreferenceItem()285 getRoutesWithNoAssociatedListingPreferenceItem() { 286 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { 287 return ImmutableList.of(); 288 } 289 Set<String> routesWithAssociatedRouteListingPreferenceItem = new HashSet<>(); 290 for (RouteListingPreferenceItemHolder element : 291 mRoutesManager.getRouteListingPreferenceItems()) { 292 String routeId = element.mItem.getRouteId(); 293 routesWithAssociatedRouteListingPreferenceItem.add(routeId); 294 } 295 296 ImmutableList.Builder<MediaRouter.RouteInfo> resultBuilder = ImmutableList.builder(); 297 for (MediaRouter.RouteInfo route : MediaRouter.getInstance(this).getRoutes()) { 298 if (!routesWithAssociatedRouteListingPreferenceItem.contains(route.getId())) { 299 resultBuilder.add(route); 300 } 301 } 302 return resultBuilder.build(); 303 } 304 305 private class RecyclerViewCallback extends ItemTouchHelper.SimpleCallback { 306 307 private static final int INDEX_UNSET = -1; 308 309 private int mDraggingFromPosition; 310 private int mDraggingToPosition; 311 RecyclerViewCallback()312 private RecyclerViewCallback() { 313 super( 314 ItemTouchHelper.UP | ItemTouchHelper.DOWN, 315 ItemTouchHelper.START | ItemTouchHelper.END); 316 mDraggingFromPosition = INDEX_UNSET; 317 mDraggingToPosition = INDEX_UNSET; 318 } 319 320 @Override onMove( @onNull RecyclerView recyclerView, RecyclerView.@NonNull ViewHolder origin, RecyclerView.@NonNull ViewHolder target)321 public boolean onMove( 322 @NonNull RecyclerView recyclerView, 323 RecyclerView.@NonNull ViewHolder origin, 324 RecyclerView.@NonNull ViewHolder target) { 325 int fromPosition = origin.getBindingAdapterPosition(); 326 int toPosition = target.getBindingAdapterPosition(); 327 if (mDraggingFromPosition == INDEX_UNSET) { 328 // A drag has started, but we wait for the clearView() call to update the route 329 // listing preference. 330 mDraggingFromPosition = fromPosition; 331 } 332 mDraggingToPosition = toPosition; 333 recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition); 334 return false; 335 } 336 337 @Override onSwiped(RecyclerView.@onNull ViewHolder viewHolder, int direction)338 public void onSwiped(RecyclerView.@NonNull ViewHolder viewHolder, int direction) { 339 ArrayList<RouteListingPreferenceItemHolder> newRouteListingPreference = 340 new ArrayList<>(mRoutesManager.getRouteListingPreferenceItems()); 341 int itemPosition = viewHolder.getBindingAdapterPosition(); 342 newRouteListingPreference.remove(itemPosition); 343 mRoutesManager.setRouteListingPreferenceItems(newRouteListingPreference); 344 viewHolder.getBindingAdapter().notifyItemRemoved(itemPosition); 345 } 346 347 @Override clearView( @onNull RecyclerView recyclerView, RecyclerView.@NonNull ViewHolder viewHolder)348 public void clearView( 349 @NonNull RecyclerView recyclerView, RecyclerView.@NonNull ViewHolder viewHolder) { 350 super.clearView(recyclerView, viewHolder); 351 if (mDraggingFromPosition != INDEX_UNSET) { 352 ArrayList<RouteListingPreferenceItemHolder> newRouteListingPreference = 353 new ArrayList<>(mRoutesManager.getRouteListingPreferenceItems()); 354 newRouteListingPreference.add( 355 mDraggingToPosition, 356 newRouteListingPreference.remove(mDraggingFromPosition)); 357 mRoutesManager.setRouteListingPreferenceItems(newRouteListingPreference); 358 } 359 mDraggingFromPosition = INDEX_UNSET; 360 mDraggingToPosition = INDEX_UNSET; 361 } 362 } 363 364 private class RouteListingPreferenceRecyclerViewAdapter 365 extends RecyclerView.Adapter<RecyclerViewItemViewHolder> { 366 @Override onCreateViewHolder( @onNull ViewGroup parent, int viewType)367 public @NonNull RecyclerViewItemViewHolder onCreateViewHolder( 368 @NonNull ViewGroup parent, int viewType) { 369 TextView textView = 370 (TextView) 371 LayoutInflater.from(parent.getContext()) 372 .inflate( 373 android.R.layout.simple_list_item_1, 374 parent, 375 /* attachToRoot= */ false); 376 return new RecyclerViewItemViewHolder(textView); 377 } 378 379 @Override onBindViewHolder(@onNull RecyclerViewItemViewHolder holder, int position)380 public void onBindViewHolder(@NonNull RecyclerViewItemViewHolder holder, int position) { 381 holder.mTextView.setText( 382 mRoutesManager.getRouteListingPreferenceItems().get(position).mRouteName); 383 } 384 385 @Override getItemCount()386 public int getItemCount() { 387 return mRoutesManager.getRouteListingPreferenceItems().size(); 388 } 389 } 390 391 private class RecyclerViewItemViewHolder extends RecyclerView.ViewHolder 392 implements View.OnClickListener { 393 394 public final TextView mTextView; 395 RecyclerViewItemViewHolder(TextView textView)396 private RecyclerViewItemViewHolder(TextView textView) { 397 super(textView); 398 mTextView = textView; 399 textView.setOnClickListener(this); 400 } 401 402 @Override onClick(View view)403 public void onClick(View view) { 404 setUpRouteListingPreferenceItemEditionDialog(getBindingAdapterPosition()); 405 } 406 } 407 408 private enum RouteListingPreferenceItemSelectionBehavior { 409 SELECTION_BEHAVIOR_NONE(RouteListingPreference.Item.SELECTION_BEHAVIOR_NONE, "None"), 410 SELECTION_BEHAVIOR_TRANSFER( 411 RouteListingPreference.Item.SELECTION_BEHAVIOR_TRANSFER, "Transfer"), 412 SELECTION_BEHAVIOR_GO_TO_APP( 413 RouteListingPreference.Item.SELECTION_BEHAVIOR_GO_TO_APP, "Go to app"); 414 415 public final int mConstant; 416 public final String mHumanReadableString; 417 RouteListingPreferenceItemSelectionBehavior( int constant, @NonNull String humanReadableString)418 RouteListingPreferenceItemSelectionBehavior( 419 int constant, @NonNull String humanReadableString) { 420 mConstant = constant; 421 mHumanReadableString = humanReadableString; 422 } 423 424 @Override toString()425 public @NonNull String toString() { 426 return mHumanReadableString; 427 } 428 fromConstant(int constant)429 public static RouteListingPreferenceItemSelectionBehavior fromConstant(int constant) { 430 switch (constant) { 431 case RouteListingPreference.Item.SELECTION_BEHAVIOR_NONE: 432 return SELECTION_BEHAVIOR_NONE; 433 case RouteListingPreference.Item.SELECTION_BEHAVIOR_TRANSFER: 434 return SELECTION_BEHAVIOR_TRANSFER; 435 case RouteListingPreference.Item.SELECTION_BEHAVIOR_GO_TO_APP: 436 return SELECTION_BEHAVIOR_GO_TO_APP; 437 default: 438 throw new IllegalArgumentException("Illegal selection behavior: " + constant); 439 } 440 } 441 } 442 443 private enum RouteListingPreferenceItemSubtext { 444 SUBTEXT_NONE(RouteListingPreference.Item.SUBTEXT_NONE, "None"), 445 SUBTEXT_ERROR_UNKNOWN(RouteListingPreference.Item.SUBTEXT_ERROR_UNKNOWN, "Unknown error"), 446 SUBTEXT_SUBSCRIPTION_REQUIRED( 447 RouteListingPreference.Item.SUBTEXT_SUBSCRIPTION_REQUIRED, "Subscription required"), 448 SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED( 449 RouteListingPreference.Item.SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED, 450 "Downloaded content disallowed"), 451 SUBTEXT_AD_ROUTING_DISALLOWED( 452 RouteListingPreference.Item.SUBTEXT_AD_ROUTING_DISALLOWED, "Ad in progress"), 453 SUBTEXT_DEVICE_LOW_POWER( 454 RouteListingPreference.Item.SUBTEXT_DEVICE_LOW_POWER, "Device in low power mode"), 455 SUBTEXT_UNAUTHORIZED(RouteListingPreference.Item.SUBTEXT_UNAUTHORIZED, "Unauthorized"), 456 SUBTEXT_TRACK_UNSUPPORTED( 457 RouteListingPreference.Item.SUBTEXT_TRACK_UNSUPPORTED, "Track unsupported"), 458 SUBTEXT_CUSTOM( 459 RouteListingPreference.Item.SUBTEXT_CUSTOM, "Custom text (placeholder value)"); 460 461 public final int mConstant; 462 public final @NonNull String mHumanReadableString; 463 RouteListingPreferenceItemSubtext(int constant, @NonNull String humanReadableString)464 RouteListingPreferenceItemSubtext(int constant, @NonNull String humanReadableString) { 465 mConstant = constant; 466 mHumanReadableString = humanReadableString; 467 } 468 469 @Override toString()470 public @NonNull String toString() { 471 return mHumanReadableString; 472 } 473 fromConstant(int constant)474 public static RouteListingPreferenceItemSubtext fromConstant(int constant) { 475 switch (constant) { 476 case RouteListingPreference.Item.SUBTEXT_NONE: 477 return SUBTEXT_NONE; 478 case RouteListingPreference.Item.SUBTEXT_ERROR_UNKNOWN: 479 return SUBTEXT_ERROR_UNKNOWN; 480 case RouteListingPreference.Item.SUBTEXT_SUBSCRIPTION_REQUIRED: 481 return SUBTEXT_SUBSCRIPTION_REQUIRED; 482 case RouteListingPreference.Item.SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED: 483 return SUBTEXT_DOWNLOADED_CONTENT_ROUTING_DISALLOWED; 484 case RouteListingPreference.Item.SUBTEXT_AD_ROUTING_DISALLOWED: 485 return SUBTEXT_AD_ROUTING_DISALLOWED; 486 case RouteListingPreference.Item.SUBTEXT_DEVICE_LOW_POWER: 487 return SUBTEXT_DEVICE_LOW_POWER; 488 case RouteListingPreference.Item.SUBTEXT_UNAUTHORIZED: 489 return SUBTEXT_UNAUTHORIZED; 490 case RouteListingPreference.Item.SUBTEXT_TRACK_UNSUPPORTED: 491 return SUBTEXT_TRACK_UNSUPPORTED; 492 case RouteListingPreference.Item.SUBTEXT_CUSTOM: 493 return SUBTEXT_CUSTOM; 494 default: 495 throw new IllegalArgumentException("Illegal subtext constant: " + constant); 496 } 497 } 498 } 499 } 500