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