Merge "Autofill to auto-fill string fixes" into honeycomb-mr1
diff --git a/res/drawable/qc_menu_selector.xml b/res/drawable/qc_menu_selector.xml
new file mode 100644
index 0000000..141f165
--- /dev/null
+++ b/res/drawable/qc_menu_selector.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+        android:drawable="@*android:drawable/list_selector_pressed_holo_dark" />
+    <item android:state_pressed="false" android:drawable="@drawable/clear" />
+</selector>
diff --git a/res/layout/qc_menu_item.xml b/res/layout/qc_menu_item.xml
new file mode 100644
index 0000000..9e4a2e8
--- /dev/null
+++ b/res/layout/qc_menu_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/title"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:minHeight="44dip"
+    android:background="@drawable/qc_menu_selector"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:gravity="center"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
+    android:paddingTop="4dip"
+    android:paddingBottom="4dip"
+     />
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index b108fd8..5084e31 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -616,6 +616,11 @@
     // menu handling callbacks
 
     @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        return true;
+    }
+
+    @Override
     public void onOptionsMenuOpened() {
     }
 
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 7a6ea41..19ad40e 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -1479,7 +1479,7 @@
                 break;
         }
         mCurrentMenuState = mMenuState;
-        return true;
+        return mUi.onPrepareOptionsMenu(menu);
     }
 
     public boolean onOptionsItemSelected(MenuItem item) {
@@ -1931,6 +1931,13 @@
                 R.dimen.bookmarkThumbnailHeight);
     }
 
+    static Bitmap createScreenshot(Tab tab, int width, int height) {
+        if ((tab != null) && (tab.getWebView() != null)) {
+            return createScreenshot(tab.getWebView(), width, height);
+        }
+        return null;
+    }
+
     private static Bitmap createScreenshot(WebView view, int width, int height) {
         // We render to a bitmap 2x the desired size so that we can then
         // re-scale it with filtering since canvas.scale doesn't filter
diff --git a/src/com/android/browser/PieControl.java b/src/com/android/browser/PieControl.java
index ad47c72..302cbc0 100644
--- a/src/com/android/browser/PieControl.java
+++ b/src/com/android/browser/PieControl.java
@@ -17,15 +17,26 @@
 package com.android.browser;
 
 import com.android.browser.view.PieItem;
+import com.android.browser.view.PieListView;
 import com.android.browser.view.PieMenu;
 
 import android.app.Activity;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.webkit.WebView;
+import android.widget.BaseAdapter;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * controller for Quick Controls pie menu
@@ -44,6 +55,7 @@
     private PieItem mBookmarks;
     private PieItem mNewTab;
     private PieItem mClose;
+    private MenuAdapter mMenuAdapter;
 
     public PieControl(Activity activity, UiController controller, XLargeUi ui) {
         mActivity = activity;
@@ -67,11 +79,14 @@
             mOptions = makeItem(
                     com.android.internal.R.drawable.ic_menu_moreoverflow_normal_holo_dark,
                     2);
+            mMenuAdapter = new MenuAdapter(mActivity, mUiController);
+            PieMenuView menusym = new PieMenuView(mActivity);
+            mOptions.setPieView(menusym);
+            menusym.setAdapter(mMenuAdapter);
             setClickListener(mBack,
                     mRefresh,
                     mForward,
                     mUrl,
-                    mOptions,
                     mBookmarks,
                     mNewTab,
                     mClose
@@ -91,6 +106,10 @@
         container.addView(mPie);
     }
 
+    protected void onMenuOpened(Menu menu) {
+        mMenuAdapter.setMenu(menu);
+    }
+
     protected void removeFromContainer(FrameLayout container) {
         container.removeView(mPie);
     }
@@ -135,8 +154,6 @@
             }
         } else if (mUrl.getView() == v) {
             mUi.showTitleBarAndEdit();
-        } else if (mOptions.getView() == v) {
-            mActivity.openOptionsMenu();
         } else if (mBookmarks.getView() == v) {
             mUiController.bookmarksOrHistoryPicker(false);
         } else if (mNewTab.getView() == v) {
@@ -152,4 +169,83 @@
         return false;
     }
 
+    private class PieMenuView extends PieListView {
+
+        /**
+         * @param ctx
+         */
+        public PieMenuView(Context ctx) {
+            super(ctx);
+        }
+
+        @Override
+        public void layout(int anchorX, int anchorY, boolean left) {
+            mActivity.openOptionsMenu();
+            super.layout(anchorX, anchorY, left);
+        }
+
+    }
+
+    private static class MenuAdapter extends BaseAdapter
+            implements OnClickListener {
+
+        List<MenuItem> mItems;
+        UiController mUiController;
+        LayoutInflater mInflater;
+
+        public MenuAdapter(Context ctx, UiController ctl) {
+            mUiController = ctl;
+            mInflater = LayoutInflater.from(ctx);
+            mItems = new ArrayList<MenuItem>();
+        }
+
+        public void setMenu(Menu menu) {
+            mItems.clear();
+            for (int i = 0; i < menu.size(); i++) {
+                MenuItem item = menu.getItem(i);
+                if (item.isEnabled() && item.isVisible()) {
+                    mItems.add(item);
+                }
+            }
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public int getCount() {
+            return mItems.size();
+        }
+
+        @Override
+        public MenuItem getItem(int position) {
+            return mItems.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public void onClick(View v) {
+            if (v.getTag() != null) {
+                mUiController.onOptionsItemSelected((MenuItem) v.getTag());
+            }
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final MenuItem item = mItems.get(position);
+            View view = mInflater.inflate(
+                    R.layout.qc_menu_item, null);
+            TextView label =
+                    (TextView) view.findViewById(R.id.title);
+            label.setText(item.getTitle());
+            label.setTag(item);
+            label.setOnClickListener(this);
+            label.setLayoutParams(new LayoutParams(240, 32));
+            return label;
+        }
+
+    }
+
 }
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 47cefbc..70028ea 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -1757,4 +1757,5 @@
             }
         }
     };
+
 }
diff --git a/src/com/android/browser/UI.java b/src/com/android/browser/UI.java
index bec7034..13f8af2 100644
--- a/src/com/android/browser/UI.java
+++ b/src/com/android/browser/UI.java
@@ -89,6 +89,8 @@
 
     public void revertVoiceTitleBar(Tab tab);
 
+    public boolean onPrepareOptionsMenu(Menu menu);
+
     public void onOptionsMenuOpened();
 
     public void onExtendedMenuOpened();
diff --git a/src/com/android/browser/UiController.java b/src/com/android/browser/UiController.java
index 551d0ce..65fa5f8 100644
--- a/src/com/android/browser/UiController.java
+++ b/src/com/android/browser/UiController.java
@@ -19,6 +19,7 @@
 import com.android.browser.UI.DropdownChangeListener;
 
 import android.content.Intent;
+import android.view.MenuItem;
 import android.webkit.WebView;
 
 import java.util.List;
@@ -88,4 +89,7 @@
     void unregisterOptionsMenuHandler(OptionsMenuHandler handler);
 
     void registerDropdownChangeListener(DropdownChangeListener d);
+
+    boolean onOptionsItemSelected(MenuItem item);
+
 }
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index d940b50..debb763 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -24,12 +24,15 @@
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
 import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.Menu;
 import android.view.View;
 import android.webkit.WebChromeClient.CustomViewCallback;
 import android.webkit.WebView;
@@ -121,15 +124,14 @@
 
     private void checkTabCount() {
         if (mUseQuickControls) {
-            int n = mTabBar.getTabCount();
-            if (n >= 2) {
-                mActionBar.show();
-            } else if (n == 1) {
+            if (mTabControl.getTabCount() == 1) {
                 mHandler.post(new Runnable() {
                     public void run() {
                         mActionBar.hide();
                     }
                 });
+            } else {
+                mActionBar.show();
             }
         }
     }
@@ -503,4 +505,14 @@
         mTitleBar.registerDropdownChangeListener(d);
     }
 
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        if (mUseQuickControls) {
+            mPieControl.onMenuOpened(menu);
+            return false;
+        } else {
+            return true;
+        }
+    }
+
 }
diff --git a/src/com/android/browser/view/BasePieView.java b/src/com/android/browser/view/BasePieView.java
new file mode 100644
index 0000000..515545a
--- /dev/null
+++ b/src/com/android/browser/view/BasePieView.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser.view;
+
+import android.database.DataSetObserver;
+import android.graphics.Canvas;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Adapter;
+
+import java.util.ArrayList;
+
+/**
+ * common code for pie views
+ */
+public abstract class BasePieView implements PieMenu.PieView {
+
+    protected Adapter mAdapter;
+    private DataSetObserver mObserver;
+    protected ArrayList<View> mViews;
+
+    protected int mCurrent;
+    protected int mChildWidth;
+    protected int mChildHeight;
+    protected int mWidth;
+    protected int mHeight;
+    protected int mLeft;
+    protected int mTop;
+
+    public BasePieView() {
+    }
+
+    public void setAdapter(Adapter adapter) {
+        mAdapter = adapter;
+        if (adapter == null) {
+            if (mAdapter != null) {
+                mAdapter.unregisterDataSetObserver(mObserver);
+            }
+            mViews = null;
+            mCurrent = -1;
+        } else {
+            mObserver = new DataSetObserver() {
+                @Override
+                public void onChanged() {
+                    buildViews();
+                }
+
+                @Override
+                public void onInvalidated() {
+                    mViews.clear();
+                }
+            };
+            mAdapter.registerDataSetObserver(mObserver);
+            setCurrent(0);
+        }
+    }
+
+    public void setCurrent(int ix) {
+        mCurrent = ix;
+    }
+
+    public Adapter getAdapter() {
+        return mAdapter;
+    }
+
+    protected void buildViews() {
+        if (mAdapter != null) {
+            final int n = mAdapter.getCount();
+            if (mViews == null) {
+                mViews = new ArrayList<View>(n);
+            } else {
+                mViews.clear();
+            }
+            mChildWidth = 0;
+            mChildHeight = 0;
+            for (int i = 0; i < n; i++) {
+                View view = mAdapter.getView(i, null, null);
+                view.measure(View.MeasureSpec.UNSPECIFIED,
+                        View.MeasureSpec.UNSPECIFIED);
+                mChildWidth = Math.max(mChildWidth, view.getMeasuredWidth());
+                mChildHeight = Math.max(mChildHeight, view.getMeasuredHeight());
+                mViews.add(view);
+            }
+        }
+    }
+
+    /**
+     * this will be called before the first draw call
+     * needs to set top, left, width, height
+     */
+    @Override
+    public abstract void layout(int anchorX, int anchorY, boolean left);
+
+    @Override
+    public abstract void draw(Canvas canvas);
+
+    protected void drawView(View view, Canvas canvas) {
+        final int state = canvas.save();
+        canvas.translate(view.getLeft(), view.getTop());
+        view.draw(canvas);
+        canvas.restoreToCount(state);
+    }
+
+    protected abstract int findChildAt(int y);
+
+    @Override
+    public boolean onTouchEvent(MotionEvent evt) {
+        int action = evt.getActionMasked();
+        int evtx = (int) evt.getX();
+        int evty = (int) evt.getY();
+        if ((evtx < mLeft) || (evtx >= mLeft + mWidth)
+                || (evty < mTop) || (evty >= mTop + mHeight)) {
+            return false;
+        }
+        switch (action) {
+            case MotionEvent.ACTION_MOVE:
+                View v = mViews.get(mCurrent);
+                setCurrent(Math.max(0, Math.min(mViews.size() -1,
+                        findChildAt(evty))));
+                View v1 = mViews.get(mCurrent);
+                if (v != v1) {
+                    v.setPressed(false);
+                    v1.setPressed(true);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                mViews.get(mCurrent).performClick();
+                mViews.get(mCurrent).setPressed(false);
+                break;
+            default:
+                break;
+        }
+        return true;
+    }
+
+}
diff --git a/src/com/android/browser/view/PieItem.java b/src/com/android/browser/view/PieItem.java
index c09dba2..84a6ac0 100644
--- a/src/com/android/browser/view/PieItem.java
+++ b/src/com/android/browser/view/PieItem.java
@@ -16,6 +16,8 @@
 
 package com.android.browser.view;
 
+import com.android.browser.view.PieMenu.PieView;
+
 import android.view.View;
 
 /**
@@ -24,6 +26,7 @@
 public class PieItem {
 
     private View mView;
+    private PieView mPieView;
     private int level;
     private float start;
     private float sweep;
@@ -36,6 +39,12 @@
         this.level = level;
     }
 
+    public PieItem(View view, int level, PieView sym) {
+        mView = view;
+        this.level = level;
+        mPieView = sym;
+    }
+
     public void setSelected(boolean s) {
         mSelected = s;
         if (mView != null) {
@@ -74,8 +83,20 @@
         return outer;
     }
 
+    public boolean isPieView() {
+        return (mPieView != null);
+    }
+
     public View getView() {
         return mView;
     }
 
+    public void setPieView(PieView sym) {
+        mPieView = sym;
+    }
+
+    public PieView getPieView() {
+        return mPieView;
+    }
+
 }
diff --git a/src/com/android/browser/view/PieListView.java b/src/com/android/browser/view/PieListView.java
new file mode 100644
index 0000000..5fee51d
--- /dev/null
+++ b/src/com/android/browser/view/PieListView.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser.view;
+
+import com.android.browser.R;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.View;
+
+/**
+ * shows views in a menu style list
+ */
+public class PieListView extends BasePieView {
+
+    private Paint mBgPaint;
+
+    public PieListView(Context ctx) {
+        mBgPaint = new Paint();
+        mBgPaint.setColor(ctx.getResources().getColor(R.color.qcMenuBackground));
+    }
+
+    /**
+     * this will be called before the first draw call
+     */
+    @Override
+    public void layout(int anchorX, int anchorY, boolean left) {
+        buildViews();
+        mWidth = mChildWidth;
+        mHeight = mChildHeight * mAdapter.getCount();
+        mLeft = anchorX + (left ? 0 : - mChildWidth);
+        mTop = anchorY - mHeight / 2;
+        if (mViews != null) {
+            layoutChildrenLinear();
+        }
+    }
+
+    protected void layoutChildrenLinear() {
+        final int n = mViews.size();
+        int top = mTop;
+        for (View view : mViews) {
+            view.layout(mLeft, top, mLeft + mChildWidth, top + mChildHeight);
+            top += mChildHeight;
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.drawRect(mLeft, mTop, mLeft + mWidth, mTop + mHeight, mBgPaint);
+        if (mViews != null) {
+            for (View view : mViews) {
+                drawView(view, canvas);
+            }
+        }
+    }
+
+    @Override
+    protected int findChildAt(int y) {
+        final int ix = (y - mTop) * mViews.size() / mHeight;
+        return ix;
+    }
+
+}
diff --git a/src/com/android/browser/view/PieMenu.java b/src/com/android/browser/view/PieMenu.java
index 98c0f59..22ebd18 100644
--- a/src/com/android/browser/view/PieMenu.java
+++ b/src/com/android/browser/view/PieMenu.java
@@ -46,6 +46,19 @@
         public boolean onOpen();
     }
 
+    /**
+     * A view like object that lives off of the pie menu
+     */
+    public interface PieView {
+
+        public void layout(int anchorX, int anchorY, boolean onleft);
+
+        public void draw(Canvas c);
+
+        public boolean onTouchEvent(MotionEvent evt);
+
+    }
+
     private Point mCenter;
     private int mRadius;
     private int mRadiusInc;
@@ -57,6 +70,7 @@
     private List<PieItem> mItems;
     private int mLevels;
     private int[] mCounts;
+    private PieView mPieView = null;
 
     private Drawable mBackground;
 
@@ -143,6 +157,7 @@
         }
         if (!show) {
             mCurrentItem = null;
+            mPieView = null;
         }
         invalidate();
     }
@@ -159,6 +174,7 @@
     private void layoutPie() {
         int inner = mRadius;
         int outer = mRadius + mRadiusInc;
+        int radius = mRadius;
         for (int i = 0; i < mLevels; i++) {
             int level = i + 1;
             float sweep = (float) Math.PI / (mCounts[level] + 1);
@@ -205,6 +221,9 @@
             for (PieItem item : mItems) {
                 drawItem(canvas, item);
             }
+            if (mPieView != null) {
+                mPieView.draw(canvas);
+            }
         }
     }
 
@@ -236,10 +255,14 @@
             }
         } else if (MotionEvent.ACTION_UP == action) {
             if (mOpen) {
+                boolean handled = false;
+                if (mPieView != null) {
+                    handled = mPieView.onTouchEvent(evt);
+                }
                 PieItem item = mCurrentItem;
                 deselect();
                 show(false);
-                if (item != null) {
+                if (!handled && (item != null)) {
                     item.getView().performClick();
                 }
                 return true;
@@ -254,6 +277,13 @@
             boolean handled = false;
             PointF polar = getPolar(x, y);
             int maxr = mRadius + mLevels * mRadiusInc + 50;
+            if (mPieView != null) {
+                handled = mPieView.onTouchEvent(evt);
+            }
+            if (handled) {
+                invalidate();
+                return false;
+            }
             if (polar.y > maxr) {
                 deselect();
                 show(false);
@@ -266,6 +296,13 @@
             PieItem item = findItem(polar);
             if (mCurrentItem != item) {
                 onEnter(item);
+                if ((item != null) && item.isPieView()) {
+                    int cx = item.getView().getLeft() + (onTheLeft()
+                            ? item.getView().getWidth() : 0);
+                    int cy = item.getView().getTop();
+                    mPieView = item.getPieView();
+                    layoutPieView(mPieView, cx, cy);
+                }
                 invalidate();
             }
         }
@@ -273,6 +310,10 @@
         return false;
     }
 
+    private void layoutPieView(PieView pv, int x, int y) {
+        pv.layout(x, y, onTheLeft());
+    }
+
     /**
      * enter a slice for a view
      * updates model only
@@ -287,6 +328,7 @@
             // clear up stack
             playSoundEffect(SoundEffectConstants.CLICK);
             item.setSelected(true);
+            mPieView = null;
         }
         mCurrentItem = item;
     }
@@ -296,6 +338,7 @@
             mCurrentItem.setSelected(false);
         }
         mCurrentItem = null;
+        mPieView = null;
     }
 
     private PointF getPolar(float x, float y) {