Bug 1126608 - Add buttons. r=ally
authorChenxia Liu <liuche@mozilla.com>
Wed, 06 May 2015 19:39:07 -0700
changeset 243970 acc34206a8ab3d111baff9d3e55007d84a43b76d
parent 243969 09b6e5f3e10d572c9c2b5950cfabfcc5bf20548b
child 243971 85b0cc1fbddce86fe0702d9f5299e9a0500a65fa
push id28761
push usercbook@mozilla.com
push dateFri, 15 May 2015 14:50:10 +0000
treeherdermozilla-central@c0e709a5baca [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersally
bugs1126608
milestone41.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 1126608 - Add buttons. r=ally
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/strings.xml.in
mobile/android/base/toolbar/SiteIdentityPopup.java
mobile/android/base/widget/DoorHanger.java
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -375,16 +375,18 @@ size. -->
      contains brackets to indicate this is not actually a username, but rather a placeholder -->
 <!ENTITY doorhanger_login_no_username "[No username]">
 <!ENTITY doorhanger_login_edit_title "Edit login">
 <!ENTITY doorhanger_login_edit_username_hint "Username">
 <!ENTITY doorhanger_login_edit_password_hint "Password">
 <!ENTITY doorhanger_login_edit_toggle "Show password">
 <!ENTITY doorhanger_login_edit_toast_error "Failed to save login">
 <!ENTITY doorhanger_login_select_message "Copy password from &formatS;?">
+<!ENTITY doorhanger_login_select_toast_copy "Password copied to clipboard">
+<!ENTITY doorhanger_login_select_toast_copy_error "Couldn\'t copy password">
 
 <!ENTITY pref_titlebar_mode "Title bar">
 <!ENTITY pref_titlebar_mode_title "Show page title">
 <!ENTITY pref_titlebar_mode_url "Show page address">
 
 <!-- Localization note (pref_scroll_title_bar2): Label for setting that controls
      whether or not the dynamic toolbar is enabled. -->
 <!ENTITY pref_scroll_title_bar2 "Full-screen browsing">
@@ -435,16 +437,17 @@ size. -->
 <!ENTITY button_ok "OK">
 <!ENTITY button_cancel "Cancel">
 <!ENTITY button_yes "Yes">
 <!ENTITY button_no "No">
 <!ENTITY button_clear_data "Clear data">
 <!ENTITY button_set "Set">
 <!ENTITY button_clear "Clear">
 <!ENTITY button_remember "Remember">
+<!ENTITY button_copy "Copy">
 
 <!ENTITY firstrun_panel_title_welcome "Welcome">
 
 <!ENTITY home_top_sites_title "Top Sites">
 <!-- Localization note (home_top_sites_add): This string is used as placeholder
      text underneath empty thumbnails in the Top Sites page on about:home. -->
 <!ENTITY home_top_sites_add "Add a site">
 
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -342,16 +342,18 @@
 
   <string name="doorhanger_login_no_username">&doorhanger_login_no_username;</string>
   <string name="doorhanger_login_edit_title">&doorhanger_login_edit_title;</string>
   <string name="doorhanger_login_edit_username_hint">&doorhanger_login_edit_username_hint;</string>
   <string name="doorhanger_login_edit_password_hint">&doorhanger_login_edit_password_hint;</string>
   <string name="doorhanger_login_edit_toggle">&doorhanger_login_edit_toggle;</string>
   <string name="doorhanger_login_edit_toast_error">&doorhanger_login_edit_toast_error;</string>
   <string name="doorhanger_login_select_message">&doorhanger_login_select_message;</string>
+  <string name="doorhanger_login_select_toast_copy">&doorhanger_login_select_toast_copy;</string>
+  <string name="doorhanger_login_select_toast_copy_error">&doorhanger_login_select_toast_copy_error;</string>
 
   <string name="pref_titlebar_mode">&pref_titlebar_mode;</string>
   <string name="pref_titlebar_mode_title">&pref_titlebar_mode_title;</string>
   <string name="pref_titlebar_mode_url">&pref_titlebar_mode_url;</string>
 
   <string name="pref_scroll_title_bar2">&pref_scroll_title_bar2;</string>
   <string name="pref_scroll_title_bar_summary">&pref_scroll_title_bar_summary;</string>
 
@@ -371,16 +373,17 @@
   <string name="button_ok">&button_ok;</string>
   <string name="button_cancel">&button_cancel;</string>
   <string name="button_clear_data">&button_clear_data;</string>
   <string name="button_set">&button_set;</string>
   <string name="button_clear">&button_clear;</string>
   <string name="button_yes">&button_yes;</string>
   <string name="button_no">&button_no;</string>
   <string name="button_remember">&button_remember;</string>
+  <string name="button_copy">&button_copy;</string>
 
   <string name="firstrun_panel_title_welcome">&firstrun_panel_title_welcome;</string>
 
   <string name="home_title">&home_title;</string>
   <string name="home_top_sites_title">&home_top_sites_title;</string>
   <string name="home_top_sites_add">&home_top_sites_add;</string>
   <string name="home_history_title">&home_history_title;</string>
   <string name="home_clear_history_button">&home_clear_history_button;</string>
--- a/mobile/android/base/toolbar/SiteIdentityPopup.java
+++ b/mobile/android/base/toolbar/SiteIdentityPopup.java
@@ -1,17 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.toolbar;
 
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.widget.Toast;
 import org.json.JSONException;
 import org.json.JSONArray;
 import org.mozilla.gecko.AboutPages;
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.SiteIdentity;
 import org.mozilla.gecko.SiteIdentity.SecurityMode;
 import org.mozilla.gecko.SiteIdentity.MixedMode;
 import org.mozilla.gecko.SiteIdentity.TrackingMode;
@@ -35,17 +39,17 @@ import org.mozilla.gecko.widget.Doorhang
 import org.mozilla.gecko.widget.SiteLogins;
 
 /**
  * SiteIdentityPopup is a singleton class that displays site identity data in
  * an arrow panel popup hanging from the lock icon in the browser toolbar.
  */
 public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListener {
 
-    public static enum ButtonType { DISABLE, ENABLE, KEEP_BLOCKING };
+    public static enum ButtonType { DISABLE, ENABLE, KEEP_BLOCKING, CANCEL, COPY };
 
     private static final String LOGTAG = "GeckoSiteIdentityPopup";
 
     private static final String MIXED_CONTENT_SUPPORT_URL =
         "https://support.mozilla.org/kb/how-does-insecure-content-affect-safety-android";
 
     private static final String TRACKING_CONTENT_SUPPORT_URL =
         "https://support.mozilla.org/kb/firefox-android-tracking-protection";
@@ -66,22 +70,22 @@ public class SiteIdentityPopup extends A
     private TextView mVerifier;
 
     private View mDivider;
 
     private DoorHanger mMixedContentNotification;
     private DoorHanger mTrackingContentNotification;
     private DoorHanger mSelectLoginDoorhanger;
 
-    private final OnButtonClickListener mButtonClickListener;
+    private final OnButtonClickListener mContentButtonClickListener;
 
     public SiteIdentityPopup(Context context) {
         super(context);
 
-        mButtonClickListener = new PopupButtonListener();
+        mContentButtonClickListener = new ContentNotificationButtonListener();
         EventDispatcher.getInstance().registerGeckoThreadListener(this, "Doorhanger:Logins");
     }
 
     @Override
     protected void init() {
         super.init();
 
         // Make the popup focusable so it doesn't inadvertently trigger click events elsewhere
@@ -158,17 +162,45 @@ public class SiteIdentityPopup extends A
             return;
         }
 
         final JSONArray logins = siteLogins.getLogins();
         if (logins.length() == 0) {
             return;
         }
 
-        final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.LOGIN, null);
+        final JSONObject login = (JSONObject) logins.get(0);
+        final OnButtonClickListener buttonClickListener = new OnButtonClickListener() {
+            @Override
+            public void onButtonClick(JSONObject response, DoorHanger doorhanger) {
+                try {
+                    final int buttonId = response.getInt("callback");
+                    if (buttonId == ButtonType.COPY.ordinal()) {
+                        final ClipboardManager manager = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
+                        final String password = login.getString("password");
+                        if (AppConstants.Versions.feature11Plus) {
+                            manager.setPrimaryClip(ClipData.newPlainText("password", password));
+                        } else {
+                            manager.setText(password);
+                        }
+                        Toast.makeText(mContext, R.string.doorhanger_login_select_toast_copy, Toast.LENGTH_SHORT).show();
+                    }
+                    dismiss();
+                } catch (JSONException e) {
+                    Log.e(LOGTAG, "Error handling Select login button click", e);
+                    Toast.makeText(mContext, R.string.doorhanger_login_select_toast_copy_error, Toast.LENGTH_SHORT).show();
+                }
+            }
+        };
+
+        final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.LOGIN, buttonClickListener);
+
+        // Set buttons.
+        config.appendButton(mContext.getString(R.string.button_cancel), ButtonType.CANCEL.ordinal());
+        config.appendButton(mContext.getString(R.string.button_copy), ButtonType.COPY.ordinal());
 
         // Set message.
         String username = ((JSONObject) logins.get(0)).getString("username");
         if (TextUtils.isEmpty(username)) {
             username = mContext.getString(R.string.doorhanger_login_no_username);
         }
 
         final String message = mContext.getString(R.string.doorhanger_login_select_message).replace(FORMAT_S, username);
@@ -243,17 +275,17 @@ public class SiteIdentityPopup extends A
         final String encrypted = siteIdentity.getEncrypted();
         mVerifier.setText(verifier + "\n" + encrypted);
     }
 
     private void addMixedContentNotification(boolean blocked) {
         // Remove any existing mixed content notification.
         removeMixedContentNotification();
 
-        final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.MIXED_CONTENT, mButtonClickListener);
+        final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.MIXED_CONTENT, mContentButtonClickListener);
         int icon;
         if (blocked) {
             icon = R.drawable.shield_enabled_doorhanger;
             config.setMessage(mContext.getString(R.string.blocked_mixed_content_message_top) + "\n\n" +
                       mContext.getString(R.string.blocked_mixed_content_message_bottom));
         } else {
             icon = R.drawable.shield_disabled_doorhanger;
             config.setMessage(mContext.getString(R.string.loaded_mixed_content_message));
@@ -275,17 +307,17 @@ public class SiteIdentityPopup extends A
             mMixedContentNotification = null;
         }
     }
 
     private void addTrackingContentNotification(boolean blocked) {
         // Remove any existing tracking content notification.
         removeTrackingContentNotification();
 
-        final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.TRACKING, mButtonClickListener);
+        final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.TRACKING, mContentButtonClickListener);
 
         int icon;
         if (blocked) {
             icon = R.drawable.shield_enabled_doorhanger;
             config.setMessage(mContext.getString(R.string.blocked_tracking_content_message_top) + "\n\n" +
                       mContext.getString(R.string.blocked_tracking_content_message_bottom));
         } else {
             icon = R.drawable.shield_disabled_doorhanger;
@@ -398,17 +430,17 @@ public class SiteIdentityPopup extends A
     public void dismiss() {
         super.dismiss();
         removeMixedContentNotification();
         removeTrackingContentNotification();
         removeSelectLoginDoorhanger();
         mDivider.setVisibility(View.GONE);
     }
 
-    private class PopupButtonListener implements OnButtonClickListener {
+    private class ContentNotificationButtonListener implements OnButtonClickListener {
         @Override
         public void onButtonClick(JSONObject response, DoorHanger doorhanger) {
             GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", response.toString());
             GeckoAppShell.sendEventToGecko(e);
             dismiss();
         }
     }
 }
--- a/mobile/android/base/widget/DoorHanger.java
+++ b/mobile/android/base/widget/DoorHanger.java
@@ -122,17 +122,16 @@ public abstract class DoorHanger extends
         final long timeout = options.optLong("timeout");
         if (timeout > 0) {
             mTimeout = timeout;
         }
     }
 
     protected void setButtons(DoorhangerConfig config) {
         final JSONArray buttons = config.getButtons();
-        final OnButtonClickListener listener = config.getButtonClickListener();
         for (int i = 0; i < buttons.length(); i++) {
             try {
                 final JSONObject buttonObject = buttons.getJSONObject(i);
                 final String label = buttonObject.getString("label");
                 final int callbackId = buttonObject.getInt("callback");
                 addButtonToLayout(label, callbackId);
             } catch (JSONException e) {
                 Log.e(LOGTAG, "Error creating doorhanger button", e);