Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / chrome / android / java / src / org / chromium / chrome / browser / appmenu / AppMenuAdapter.java
index 6bf7f43..2b60292 100644 (file)
@@ -4,6 +4,10 @@
 
 package org.chromium.chrome.browser.appmenu;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
@@ -12,10 +16,15 @@ import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
 import android.widget.ListView;
 import android.widget.TextView;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.ui.base.LocalizationUtils;
+import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
 import java.util.List;
 
@@ -23,7 +32,7 @@ import java.util.List;
  * ListAdapter to customize the view of items in the list.
  */
 class AppMenuAdapter extends BaseAdapter {
-    private static final int VIEW_TYPE_COUNT = 4;
+    private static final int VIEW_TYPE_COUNT = 5;
 
     /**
      * Regular Android menu item that contains a title and an icon if icon is specified.
@@ -42,17 +51,38 @@ class AppMenuAdapter extends BaseAdapter {
      * Menu item that has four buttons. Every one of these buttons is displayed as an icon.
      */
     private static final int FOUR_BUTTON_MENU_ITEM = 3;
+    /**
+     * Menu item that has two buttons, the first one is a title and the second is a menu icon.
+     * This is similar to {@link #TITLE_BUTTON_MENU_ITEM} but has some slight layout differences.
+     */
+    private static final int MENU_BUTTON_MENU_ITEM = 4;
+
+    /** MenuItem Animation Constants */
+    private static final int ENTER_ITEM_DURATION_MS = 350;
+    private static final int ENTER_ITEM_BASE_DELAY_MS = 80;
+    private static final int ENTER_ITEM_ADDL_DELAY_MS = 30;
+    private static final float ENTER_STANDARD_ITEM_OFFSET_Y_DP = -10.f;
+    private static final float ENTER_STANDARD_ITEM_OFFSET_X_DP = 10.f;
+
+    /** Menu Button Layout Constants */
+    private static final float MENU_BUTTON_WIDTH_DP = 59.f;
+    private static final float MENU_BUTTON_START_PADDING_DP = 21.f;
 
     private final AppMenu mAppMenu;
     private final LayoutInflater mInflater;
     private final List<MenuItem> mMenuItems;
     private final int mNumMenuItems;
+    private final boolean mShowMenuButton;
+    private final float mDpToPx;
 
-    public AppMenuAdapter(AppMenu appMenu, List<MenuItem> menuItems, LayoutInflater inflater) {
+    public AppMenuAdapter(AppMenu appMenu, List<MenuItem> menuItems, LayoutInflater inflater,
+            boolean showMenuButton) {
         mAppMenu = appMenu;
         mMenuItems = menuItems;
         mInflater = inflater;
         mNumMenuItems = menuItems.size();
+        mShowMenuButton = showMenuButton;
+        mDpToPx = inflater.getContext().getResources().getDisplayMetrics().density;
     }
 
     @Override
@@ -67,14 +97,17 @@ class AppMenuAdapter extends BaseAdapter {
 
     @Override
     public int getItemViewType(int position) {
-        if (getItem(position).hasSubMenu()) {
-            if (getItem(position).getSubMenu().size() == 4) {
-                return FOUR_BUTTON_MENU_ITEM;
-            } else if (getItem(position).getSubMenu().size() == 3) {
-                return THREE_BUTTON_MENU_ITEM;
-            } else if (getItem(position).getSubMenu().size() == 2) {
-                return TITLE_BUTTON_MENU_ITEM;
-            }
+        MenuItem item = getItem(position);
+        boolean hasMenuButton = mShowMenuButton && position == 0;
+        int viewCount = item.hasSubMenu() ? item.getSubMenu().size() : 1;
+        if (hasMenuButton) viewCount++;
+
+        if (viewCount == 4) {
+            return FOUR_BUTTON_MENU_ITEM;
+        } else if (viewCount == 3) {
+            return THREE_BUTTON_MENU_ITEM;
+        } else if (viewCount == 2) {
+            return hasMenuButton ? MENU_BUTTON_MENU_ITEM : TITLE_BUTTON_MENU_ITEM;
         }
         return STANDARD_MENU_ITEM;
     }
@@ -94,6 +127,7 @@ class AppMenuAdapter extends BaseAdapter {
 
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
+        final boolean hasMenuButton = mShowMenuButton && position == 0;
         final MenuItem item = getItem(position);
         switch (getItemViewType(position)) {
             case STANDARD_MENU_ITEM: {
@@ -104,6 +138,8 @@ class AppMenuAdapter extends BaseAdapter {
                     holder.text = (TextView) convertView.findViewById(R.id.menu_item_text);
                     holder.image = (AppMenuItemIcon) convertView.findViewById(R.id.menu_item_icon);
                     convertView.setTag(holder);
+                    convertView.setTag(R.id.menu_item_enter_anim_id,
+                            buildStandardItemEnterAnimator(convertView, position));
                 } else {
                     holder = (StandardMenuItemViewHolder) convertView.getTag();
                 }
@@ -133,16 +169,23 @@ class AppMenuAdapter extends BaseAdapter {
                 if (convertView == null) {
                     holder = new ThreeButtonMenuItemViewHolder();
                     convertView = mInflater.inflate(R.layout.three_button_menu_item, parent, false);
-                    holder.buttonOne = (ImageButton) convertView.findViewById(R.id.button_one);
-                    holder.buttonTwo = (ImageButton) convertView.findViewById(R.id.button_two);
-                    holder.buttonThree = (ImageButton) convertView.findViewById(R.id.button_three);
+                    holder.buttons[0] = (ImageButton) convertView.findViewById(R.id.button_one);
+                    holder.buttons[1] = (ImageButton) convertView.findViewById(R.id.button_two);
+                    holder.buttons[2] = (ImageButton) convertView.findViewById(R.id.button_three);
                     convertView.setTag(holder);
+                    convertView.setTag(R.id.menu_item_enter_anim_id,
+                            buildIconItemEnterAnimator(holder.buttons, hasMenuButton));
                 } else {
                     holder = (ThreeButtonMenuItemViewHolder) convertView.getTag();
                 }
-                setupImageButton(holder.buttonOne, item.getSubMenu().getItem(0));
-                setupImageButton(holder.buttonTwo, item.getSubMenu().getItem(1));
-                setupImageButton(holder.buttonThree, item.getSubMenu().getItem(2));
+                setupImageButton(holder.buttons[0], item.getSubMenu().getItem(0));
+                setupImageButton(holder.buttons[1], item.getSubMenu().getItem(1));
+                if (hasMenuButton) {
+                    setupMenuButton(holder.buttons[3]);
+                } else {
+                    setupImageButton(holder.buttons[2], item.getSubMenu().getItem(2));
+                }
+
                 convertView.setFocusable(false);
                 convertView.setEnabled(false);
                 break;
@@ -152,34 +195,47 @@ class AppMenuAdapter extends BaseAdapter {
                 if (convertView == null) {
                     holder = new FourButtonMenuItemViewHolder();
                     convertView = mInflater.inflate(R.layout.four_button_menu_item, parent, false);
-                    holder.buttonOne = (ImageButton) convertView.findViewById(R.id.button_one);
-                    holder.buttonTwo = (ImageButton) convertView.findViewById(R.id.button_two);
-                    holder.buttonThree = (ImageButton) convertView.findViewById(R.id.button_three);
-                    holder.buttonFour = (ImageButton) convertView.findViewById(R.id.button_four);
+                    holder.buttons[0] = (ImageButton) convertView.findViewById(R.id.button_one);
+                    holder.buttons[1] = (ImageButton) convertView.findViewById(R.id.button_two);
+                    holder.buttons[2] = (ImageButton) convertView.findViewById(R.id.button_three);
+                    holder.buttons[3] = (ImageButton) convertView.findViewById(R.id.button_four);
                     convertView.setTag(holder);
+                    convertView.setTag(R.id.menu_item_enter_anim_id,
+                            buildIconItemEnterAnimator(holder.buttons, hasMenuButton));
                 } else {
                     holder = (FourButtonMenuItemViewHolder) convertView.getTag();
                 }
-                setupImageButton(holder.buttonOne, item.getSubMenu().getItem(0));
-                setupImageButton(holder.buttonTwo, item.getSubMenu().getItem(1));
-                setupImageButton(holder.buttonThree, item.getSubMenu().getItem(2));
-                setupImageButton(holder.buttonFour, item.getSubMenu().getItem(3));
+                setupImageButton(holder.buttons[0], item.getSubMenu().getItem(0));
+                setupImageButton(holder.buttons[1], item.getSubMenu().getItem(1));
+                setupImageButton(holder.buttons[2], item.getSubMenu().getItem(2));
+                if (hasMenuButton) {
+                    setupMenuButton(holder.buttons[3]);
+                } else {
+                    setupImageButton(holder.buttons[3], item.getSubMenu().getItem(3));
+                }
                 convertView.setFocusable(false);
                 convertView.setEnabled(false);
                 break;
             }
-            case TITLE_BUTTON_MENU_ITEM: {
+            case TITLE_BUTTON_MENU_ITEM:
+                // Fall through.
+            case MENU_BUTTON_MENU_ITEM: {
                 TitleButtonMenuItemViewHolder holder = null;
                 if (convertView == null) {
                     holder = new TitleButtonMenuItemViewHolder();
                     convertView = mInflater.inflate(R.layout.title_button_menu_item, parent, false);
                     holder.title = (TextView) convertView.findViewById(R.id.title);
                     holder.button = (ImageButton) convertView.findViewById(R.id.button);
+
+                    View animatedView = hasMenuButton ? holder.title : convertView;
+
                     convertView.setTag(holder);
+                    convertView.setTag(R.id.menu_item_enter_anim_id,
+                            buildStandardItemEnterAnimator(animatedView, position));
                 } else {
                     holder = (TitleButtonMenuItemViewHolder) convertView.getTag();
                 }
-                final MenuItem titleItem = item.getSubMenu().getItem(0);
+                final MenuItem titleItem = item.hasSubMenu() ? item.getSubMenu().getItem(0) : item;
                 holder.title.setText(titleItem.getTitle());
                 holder.title.setEnabled(titleItem.isEnabled());
                 holder.title.setFocusable(titleItem.isEnabled());
@@ -189,7 +245,11 @@ class AppMenuAdapter extends BaseAdapter {
                         mAppMenu.onItemClick(titleItem);
                     }
                 });
-                if (item.getSubMenu().getItem(1).getIcon() != null) {
+
+                if (hasMenuButton) {
+                    holder.button.setVisibility(View.VISIBLE);
+                    setupMenuButton(holder.button);
+                } else if (item.getSubMenu().getItem(1).getIcon() != null) {
                     holder.button.setVisibility(View.VISIBLE);
                     setupImageButton(holder.button, item.getSubMenu().getItem(1));
                 } else {
@@ -206,7 +266,11 @@ class AppMenuAdapter extends BaseAdapter {
     }
 
     private void setupImageButton(ImageButton button, final MenuItem item) {
+        // Store and recover the level of image as button.setimageDrawable
+        // resets drawable to default level.
+        int currentLevel = item.getIcon().getLevel();
         button.setImageDrawable(item.getIcon());
+        item.getIcon().setLevel(currentLevel);
         button.setContentDescription(item.getTitle());
         button.setEnabled(item.isEnabled());
         button.setFocusable(item.isEnabled());
@@ -218,22 +282,111 @@ class AppMenuAdapter extends BaseAdapter {
         });
     }
 
+    private void setupMenuButton(ImageButton button) {
+        button.setImageResource(R.drawable.btn_menu_pressed);
+        button.setContentDescription(button.getResources().getString(R.string.menu_dismiss_btn));
+        button.setEnabled(true);
+        button.setFocusable(true);
+        button.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mAppMenu.dismiss();
+            }
+        });
+
+        // Set the button layout to make it properly line up with any underlying menu button
+        ApiCompatibilityUtils.setPaddingRelative(
+                button, (int) (MENU_BUTTON_START_PADDING_DP * mDpToPx), 0, 0, 0);
+        button.getLayoutParams().width = (int) (MENU_BUTTON_WIDTH_DP * mDpToPx);
+        button.setScaleType(ScaleType.CENTER);
+    }
+
+    /**
+     * This builds an {@link Animator} for the enter animation of a standard menu item.  This means
+     * it will animate the alpha from 0 to 1 and translate the view from -10dp to 0dp on the y axis.
+     *
+     * @param view     The menu item {@link View} to be animated.
+     * @param position The position in the menu.  This impacts the start delay of the animation.
+     * @return         The {@link Animator}.
+     */
+    private Animator buildStandardItemEnterAnimator(final View view, int position) {
+        final float offsetYPx = ENTER_STANDARD_ITEM_OFFSET_Y_DP * mDpToPx;
+        final int startDelay = ENTER_ITEM_BASE_DELAY_MS + ENTER_ITEM_ADDL_DELAY_MS * position;
+
+        AnimatorSet animation = new AnimatorSet();
+        animation.playTogether(
+                ObjectAnimator.ofFloat(view, View.ALPHA, 0.f, 1.f),
+                ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, offsetYPx, 0.f));
+        animation.setDuration(ENTER_ITEM_DURATION_MS);
+        animation.setStartDelay(startDelay);
+        animation.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
+
+        animation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                view.setAlpha(0.f);
+            }
+        });
+        return animation;
+    }
+
+    /**
+     * This builds an {@link Animator} for the enter animation of icon row menu items.  This means
+     * it will animate the alpha from 0 to 1 and translate the views from 10dp to 0dp on the x axis.
+     *
+     * @param views        The list if icons in the menu item that should be animated.
+     * @param skipLastItem Whether or not the last item should be animated or not.
+     * @return             The {@link Animator}.
+     */
+    private Animator buildIconItemEnterAnimator(final ImageView[] views, boolean skipLastItem) {
+        final boolean rtl = LocalizationUtils.isLayoutRtl();
+        final float offsetXPx = ENTER_STANDARD_ITEM_OFFSET_X_DP * mDpToPx * (rtl ? -1.f : 1.f);
+        final int maxViewsToAnimate = views.length - (skipLastItem ? 1 : 0);
+
+        AnimatorSet animation = new AnimatorSet();
+        AnimatorSet.Builder builder = null;
+        for (int i = 0; i < maxViewsToAnimate; i++) {
+            final int startDelay = ENTER_ITEM_ADDL_DELAY_MS * i;
+
+            Animator alpha = ObjectAnimator.ofFloat(views[i], View.ALPHA, 0.f, 1.f);
+            Animator translate = ObjectAnimator.ofFloat(views[i], View.TRANSLATION_X, offsetXPx, 0);
+            alpha.setStartDelay(startDelay);
+            translate.setStartDelay(startDelay);
+            alpha.setDuration(ENTER_ITEM_DURATION_MS);
+            translate.setDuration(ENTER_ITEM_DURATION_MS);
+
+            if (builder == null) {
+                builder = animation.play(alpha);
+            } else {
+                builder.with(alpha);
+            }
+            builder.with(translate);
+        }
+        animation.setStartDelay(ENTER_ITEM_BASE_DELAY_MS);
+        animation.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
+
+        animation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                for (int i = 0; i < maxViewsToAnimate; i++) {
+                    views[i].setAlpha(0.f);
+                }
+            }
+        });
+        return animation;
+    }
+
     static class StandardMenuItemViewHolder {
         public TextView text;
         public AppMenuItemIcon image;
     }
 
     static class ThreeButtonMenuItemViewHolder {
-        public ImageButton buttonOne;
-        public ImageButton buttonTwo;
-        public ImageButton buttonThree;
+        public ImageButton[] buttons = new ImageButton[3];
     }
 
     static class FourButtonMenuItemViewHolder {
-        public ImageButton buttonOne;
-        public ImageButton buttonTwo;
-        public ImageButton buttonThree;
-        public ImageButton buttonFour;
+        public ImageButton[] buttons = new ImageButton[4];
     }
 
     static class TitleButtonMenuItemViewHolder {