Bug 1438994 - Make all fields final in AuthenticationOptions, MediaSource, and Choice classes. r=snorp,jchen
authorDylan Roeh <droeh@mozilla.com>
Thu, 01 Mar 2018 14:20:25 -0500
changeset 461136 cf67ac6f58d0fc08af06d9bd6f0247e9288e0568
parent 461135 2e915e01f05d02c2e39161733615af6f16982f29
child 461137 8fc2c103027ba37bd50dec5e2fe8b79d3d68c28c
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, jchen
bugs1438994
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1438994 - Make all fields final in AuthenticationOptions, MediaSource, and Choice classes. r=snorp,jchen Make all fields final in AuthenticationOptions, MediaSource, and Choice classes in GeckoSession. Also updates BasicGeckoViewPrompt and GeckoViewActivity to work around these restrictions.
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/BasicGeckoViewPrompt.java
mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -1675,57 +1675,57 @@ public class GeckoSession extends LayerS
              * Display choices in a list that allows multiple selections.
              */
             public static final int CHOICE_TYPE_MULTIPLE = 3;
 
             /**
              * A boolean indicating if the item is disabled. Item should not be
              * selectable if this is true.
              */
-            public boolean disabled;
+            public final boolean disabled;
 
             /**
              * A String giving the URI of the item icon, or null if none exists
              * (only valid for menus)
              */
-            public String icon;
+            public final String icon;
 
             /**
              * A String giving the ID of the item or group
              */
-            public String id;
+            public final String id;
 
             /**
              * A Choice array of sub-items in a group, or null if not a group
              */
-            public Choice[] items;
+            public final Choice[] items;
 
             /**
              * A string giving the label for displaying the item or group
              */
-            public String label;
+            public final String label;
 
             /**
              * A boolean indicating if the item should be pre-selected
              * (pre-checked for menu items)
              */
-            public boolean selected;
+            public final boolean selected;
 
             /**
              * A boolean indicating if the item should be a menu separator
              * (only valid for menus)
              */
-            public boolean separator;
+            public final boolean separator;
 
             /* package */ Choice(GeckoBundle choice) {
                 disabled = choice.getBoolean("disabled");
                 icon = choice.getString("icon");
                 id = choice.getString("id");
                 label = choice.getString("label");
-                selected = choice.getBoolean("label");
+                selected = choice.getBoolean("selected");
                 separator = choice.getBoolean("separator");
 
                 GeckoBundle[] choices = choice.getBundleArray("items");
                 if (choices == null) {
                     items = null;
                 } else {
                     items = new Choice[choices.length];
                     for (int i = 0; i < choices.length; i++) {
@@ -2053,43 +2053,43 @@ public class GeckoSession extends LayerS
             /**
              * The media type is audio.
              */
             public static final int TYPE_AUDIO = 1;
 
             /**
              * A string giving the origin-specific source identifier.
              */
-            public String id;
+            public final String id;
 
             /**
              * A string giving the non-origin-specific source identifier.
              */
-            public String rawId;
+            public final String rawId;
 
             /**
              * A string giving the name of the video source from the system
              * (for example, "Camera 0, Facing back, Orientation 90").
              * May be empty.
              */
-            public String name;
+            public final String name;
 
             /**
              * An int giving the media source type.
              * Possible values for a video source are:
              * SOURCE_CAMERA, SOURCE_SCREEN, SOURCE_APPLICATION, SOURCE_WINDOW, SOURCE_BROWSER, and SOURCE_OTHER.
              * Possible values for an audio source are:
              * SOURCE_MICROPHONE, SOURCE_AUDIOCAPTURE, and SOURCE_OTHER.
              */
-            public int source;
+            public final int source;
 
             /**
              * An int giving the type of media, must be either TYPE_VIDEO or TYPE_AUDIO.
              */
-            public int type;
+            public final int type;
 
             private static int getSourceFromString(String src) {
                 // The strings here should match those in MediaSourceEnum in MediaStreamTrack.webidl
                 if ("camera".equals(src)) {
                     return SOURCE_CAMERA;
                 } else if ("screen".equals(src)) {
                     return SOURCE_SCREEN;
                 } else if ("application".equals(src)) {
@@ -2115,19 +2115,19 @@ public class GeckoSession extends LayerS
                     return TYPE_VIDEO;
                 } else if ("audio".equals(type)) {
                     return TYPE_AUDIO;
                 } else {
                     throw new IllegalArgumentException("String: " + type + " is not a valid media type string");
                 }
             }
 
-            public MediaSource(GeckoBundle media) {
+            /* package */ MediaSource(GeckoBundle media) {
                 id = media.getString("id");
-                rawId = media.getString("id");
+                rawId = media.getString("rawId");
                 name = media.getString("name");
                 source = getSourceFromString(media.getString("source"));
                 type = getTypeFromString(media.getString("type"));
             }
         }
 
         /**
          * Callback interface for notifying the result of a media permission request,
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/BasicGeckoViewPrompt.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/BasicGeckoViewPrompt.java
@@ -255,29 +255,46 @@ final class BasicGeckoViewPrompt impleme
                         } else {
                             callback.confirm(password.getText().toString());
                         }
                     }
                 });
         createStandardDialog(addCheckbox(builder, container, callback), callback).show();
     }
 
-    private void addChoiceItems(final int type, final ArrayAdapter<Choice> list,
+    private static class ModifiableChoice {
+        public boolean modifiableSelected;
+        public String modifiableLabel;
+        public final Choice choice;
+
+        public ModifiableChoice(Choice c) {
+            choice = c;
+            modifiableSelected = choice.selected;
+            modifiableLabel = choice.label;
+        }
+    }
+
+    private void addChoiceItems(final int type, final ArrayAdapter<ModifiableChoice> list,
                                 final Choice[] items, final String indent) {
         if (type == Choice.CHOICE_TYPE_MENU) {
-            list.addAll(items);
+            for (final Choice item : items) {
+                list.add(new ModifiableChoice(item));
+            }
             return;
         }
 
         for (final Choice item : items) {
+            final ModifiableChoice modItem = new ModifiableChoice(item);
+
             final Choice[] children = item.items;
+
             if (indent != null && children == null) {
-                item.label = indent + item.label;
+                modItem.modifiableLabel = indent + modItem.modifiableLabel;
             }
-            list.add(item);
+            list.add(modItem);
 
             if (children != null) {
                 final String newIndent;
                 if (type == Choice.CHOICE_TYPE_SINGLE || type == Choice.CHOICE_TYPE_MULTIPLE) {
                     newIndent = (indent != null) ? indent + '\t' : "\t";
                 } else {
                     newIndent = null;
                 }
@@ -297,17 +314,17 @@ final class BasicGeckoViewPrompt impleme
         final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
         addStandardLayout(builder, title, msg);
 
         final ListView list = new ListView(builder.getContext());
         if (type == Choice.CHOICE_TYPE_MULTIPLE) {
             list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
         }
 
-        final ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(
+        final ArrayAdapter<ModifiableChoice> adapter = new ArrayAdapter<ModifiableChoice>(
                 builder.getContext(), android.R.layout.simple_list_item_1) {
             private static final int TYPE_MENU_ITEM = 0;
             private static final int TYPE_MENU_CHECK = 1;
             private static final int TYPE_SEPARATOR = 2;
             private static final int TYPE_GROUP = 3;
             private static final int TYPE_SINGLE = 4;
             private static final int TYPE_MULTIPLE = 5;
             private static final int TYPE_COUNT = 6;
@@ -317,38 +334,38 @@ final class BasicGeckoViewPrompt impleme
 
             @Override
             public int getViewTypeCount() {
                 return TYPE_COUNT;
             }
 
             @Override
             public int getItemViewType(final int position) {
-                final Choice item = getItem(position);
-                if (item.separator) {
+                final ModifiableChoice item = getItem(position);
+                if (item.choice.separator) {
                     return TYPE_SEPARATOR;
                 } else if (type == Choice.CHOICE_TYPE_MENU) {
-                    return item.selected ? TYPE_MENU_CHECK : TYPE_MENU_ITEM;
-                } else if (item.items != null) {
+                    return item.modifiableSelected ? TYPE_MENU_CHECK : TYPE_MENU_ITEM;
+                } else if (item.choice.items != null) {
                     return TYPE_GROUP;
                 } else if (type == Choice.CHOICE_TYPE_SINGLE) {
                     return TYPE_SINGLE;
                 } else if (type == Choice.CHOICE_TYPE_MULTIPLE) {
                     return TYPE_MULTIPLE;
                 } else {
                     throw new UnsupportedOperationException();
                 }
             }
 
             @Override
             public boolean isEnabled(final int position) {
-                final Choice item = getItem(position);
-                return !item.separator && !item.disabled &&
+                final ModifiableChoice item = getItem(position);
+                return !item.choice.separator && !item.choice.disabled &&
                         ((type != Choice.CHOICE_TYPE_SINGLE && type != Choice.CHOICE_TYPE_MULTIPLE) ||
-                         item.items != null);
+                         item.choice.items != null);
             }
 
             @Override
             public View getView(final int position, View view,
                                 final ViewGroup parent) {
                 final int itemType = getItemViewType(position);
                 final int layoutId;
                 if (itemType == TYPE_SEPARATOR) {
@@ -378,22 +395,22 @@ final class BasicGeckoViewPrompt impleme
 
                 if (view == null) {
                     if (mInflater == null) {
                         mInflater = LayoutInflater.from(builder.getContext());
                     }
                     view = mInflater.inflate(layoutId, parent, false);
                 }
 
-                final Choice item = getItem(position);
+                final ModifiableChoice item = getItem(position);
                 final TextView text = (TextView) view;
-                text.setEnabled(!item.disabled);
-                text.setText(item.label);
+                text.setEnabled(!item.choice.disabled);
+                text.setText(item.modifiableLabel);
                 if (view instanceof CheckedTextView) {
-                    final boolean selected = item.selected;
+                    final boolean selected = item.modifiableSelected;
                     if (itemType == TYPE_MULTIPLE) {
                         list.setItemChecked(position, selected);
                     } else {
                         ((CheckedTextView) view).setChecked(selected);
                     }
                 }
                 return view;
             }
@@ -405,53 +422,53 @@ final class BasicGeckoViewPrompt impleme
 
         final AlertDialog dialog;
         if (type == Choice.CHOICE_TYPE_SINGLE || type == Choice.CHOICE_TYPE_MENU) {
             dialog = createStandardDialog(builder, callback);
             list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                 @Override
                 public void onItemClick(final AdapterView<?> parent, final View v,
                                         final int position, final long id) {
-                    final Choice item = adapter.getItem(position);
+                    final ModifiableChoice item = adapter.getItem(position);
                     if (type == Choice.CHOICE_TYPE_MENU) {
-                        final Choice[] children = item.items;
+                        final Choice[] children = item.choice.items;
                         if (children != null) {
                             // Show sub-menu.
                             dialog.setOnDismissListener(null);
                             dialog.dismiss();
-                            onChoicePrompt(session, item.label, /* msg */ null,
+                            onChoicePrompt(session, item.modifiableLabel, /* msg */ null,
                                             type, children, callback);
                             return;
                         }
                     }
-                    callback.confirm(item);
+                    callback.confirm(item.choice);
                     dialog.dismiss();
                 }
             });
         } else if (type == Choice.CHOICE_TYPE_MULTIPLE) {
             list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                 @Override
                 public void onItemClick(final AdapterView<?> parent, final View v,
                                         final int position, final long id) {
-                    final Choice item = adapter.getItem(position);
-                    item.selected = ((CheckedTextView) v).isChecked();
+                    final ModifiableChoice item = adapter.getItem(position);
+                    item.modifiableSelected = ((CheckedTextView) v).isChecked();
                 }
             });
             builder.setNegativeButton(android.R.string.cancel, /* listener */ null)
                    .setPositiveButton(android.R.string.ok,
                                       new DialogInterface.OnClickListener() {
                 @Override
                 public void onClick(final DialogInterface dialog,
                                     final int which) {
                     final int len = adapter.getCount();
                     ArrayList<String> items = new ArrayList<>(len);
                     for (int i = 0; i < len; i++) {
-                        final Choice item = adapter.getItem(i);
-                        if (item.selected) {
-                            items.add(item.id);
+                        final ModifiableChoice item = adapter.getItem(i);
+                        if (item.modifiableSelected) {
+                            items.add(item.choice.id);
                         }
                     }
                     callback.confirm(items.toArray(new String[items.size()]));
                 }
             });
             dialog = createStandardDialog(builder, callback);
         } else {
             throw new UnsupportedOperationException();
@@ -804,23 +821,23 @@ final class BasicGeckoViewPrompt impleme
                    public void onDismiss(final DialogInterface dialog) {
                        callback.reject();
                    }
                });
         dialog.show();
     }
 
     private Spinner addMediaSpinner(final Context context, final ViewGroup container,
-                                    final MediaSource[] sources) {
+                                    final MediaSource[] sources, final String[] sourceNames) {
         final ArrayAdapter<MediaSource> adapter = new ArrayAdapter<MediaSource>(
                 context, android.R.layout.simple_spinner_item) {
             private View convertView(final int position, final View view) {
                 if (view != null) {
                     final MediaSource item = getItem(position);
-                    ((TextView) view).setText(item.name);
+                    ((TextView) view).setText(sourceNames != null ? sourceNames[position] : item.name);
                 }
                 return view;
             }
 
             @Override
             public View getView(final int position, View view,
                                 final ViewGroup parent) {
                 return convertView(position, super.getView(position, view, parent));
@@ -839,35 +856,36 @@ final class BasicGeckoViewPrompt impleme
         spinner.setAdapter(adapter);
         spinner.setSelection(0);
         container.addView(spinner);
         return spinner;
     }
 
     public void onMediaPrompt(final GeckoSession session, final String title,
                                final MediaSource[] video, final MediaSource[] audio,
+                               final String[] videoNames, final String[] audioNames,
                                final GeckoSession.PermissionDelegate.MediaCallback callback) {
         final Activity activity = mActivity;
         if (activity == null || (video == null && audio == null)) {
             callback.reject();
             return;
         }
         final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
         final LinearLayout container = addStandardLayout(builder, title, /* msg */ null);
 
         final Spinner videoSpinner;
         if (video != null) {
-            videoSpinner = addMediaSpinner(builder.getContext(), container, video);
+            videoSpinner = addMediaSpinner(builder.getContext(), container, video, videoNames);
         } else {
             videoSpinner = null;
         }
 
         final Spinner audioSpinner;
         if (audio != null) {
-            audioSpinner = addMediaSpinner(builder.getContext(), container, audio);
+            audioSpinner = addMediaSpinner(builder.getContext(), container, audio, audioNames);
         } else {
             audioSpinner = null;
         }
 
         builder.setNegativeButton(android.R.string.cancel, /* listener */ null)
                .setPositiveButton(android.R.string.ok,
                                   new DialogInterface.OnClickListener() {
                     @Override
@@ -884,9 +902,15 @@ final class BasicGeckoViewPrompt impleme
         dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                     @Override
                     public void onDismiss(final DialogInterface dialog) {
                         callback.reject();
                     }
                 });
         dialog.show();
     }
+
+    public void onMediaPrompt(final GeckoSession session, final String title,
+                               final MediaSource[] video, final MediaSource[] audio,
+                               final GeckoSession.PermissionDelegate.MediaCallback callback) {
+        onMediaPrompt(session, title, video, audio, null, null, callback);
+    }
 }
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -286,60 +286,63 @@ public class GeckoViewActivity extends A
             }
 
             final String title = getString(resId, Uri.parse(uri).getAuthority());
             final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt)
                     mGeckoSession.getPromptDelegate();
             prompt.onPermissionPrompt(session, title, callback);
         }
 
-        private void normalizeMediaName(final MediaSource[] sources) {
+        private String[] normalizeMediaName(final MediaSource[] sources) {
             if (sources == null) {
-                return;
+                return null;
             }
-            for (final MediaSource source : sources) {
-                final int mediaSource = source.source;
-                String name = source.name;
+
+            String[] res = new String[sources.length];
+            for (int i = 0; i < sources.length; i++) {
+                final int mediaSource = sources[i].source;
+                final String name = sources[i].name;
                 if (MediaSource.SOURCE_CAMERA == mediaSource) {
                     if (name.toLowerCase(Locale.ENGLISH).contains("front")) {
-                        name = getString(R.string.media_front_camera);
+                        res[i] = getString(R.string.media_front_camera);
                     } else {
-                        name = getString(R.string.media_back_camera);
+                        res[i] = getString(R.string.media_back_camera);
                     }
                 } else if (!name.isEmpty()) {
-                    continue;
+                    res[i] = name;
                 } else if (MediaSource.SOURCE_MICROPHONE == mediaSource) {
-                    name = getString(R.string.media_microphone);
+                    res[i] = getString(R.string.media_microphone);
                 } else {
-                    name = getString(R.string.media_other);
+                    res[i] = getString(R.string.media_other);
                 }
-                source.name = name;
             }
+
+            return res;
         }
 
         @Override
         public void onMediaPermissionRequest(final GeckoSession session, final String uri,
                                            final MediaSource[] video, final MediaSource[] audio,
                                            final MediaCallback callback) {
             final String host = Uri.parse(uri).getAuthority();
             final String title;
             if (audio == null) {
                 title = getString(R.string.request_video, host);
             } else if (video == null) {
                 title = getString(R.string.request_audio, host);
             } else {
                 title = getString(R.string.request_media, host);
             }
 
-            normalizeMediaName(video);
-            normalizeMediaName(audio);
+            String[] videoNames = normalizeMediaName(video);
+            String[] audioNames = normalizeMediaName(audio);
 
             final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt)
                     mGeckoSession.getPromptDelegate();
-            prompt.onMediaPrompt(session, title, video, audio, callback);
+            prompt.onMediaPrompt(session, title, video, audio, videoNames, audioNames, callback);
         }
     }
 
     private class Navigation implements GeckoSession.NavigationDelegate {
         @Override
         public void onLocationChange(GeckoSession session, final String url) {
         }