Merge "Added tests for WebView accessibility no JS"
diff --git a/packages/SystemUI/res/drawable-mdpi/pocket_drag_pattern.png b/packages/SystemUI/res/drawable-mdpi/pocket_drag_pattern.png
new file mode 100644
index 0000000..abde010
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/pocket_drag_pattern.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/pocket_drag_bg.xml b/packages/SystemUI/res/drawable/pocket_drag_bg.xml
new file mode 100644
index 0000000..573a702
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pocket_drag_bg.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<bitmap
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:tileMode="repeat"
+    android:src="@drawable/pocket_drag_pattern"
+    />
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 6c173c9..b97b9ca 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -91,6 +91,15 @@
         </RelativeLayout>
     </FrameLayout>
 
+    <view
+        class="com.android.systemui.statusbar.tablet.ShirtPocket$DropZone"
+        android:id="@+id/drop_target"
+        android:layout_width="512dp"
+        android:layout_height="@*android:dimen/status_bar_height"
+        android:background="@drawable/pocket_drag_bg"
+        android:layout_gravity="right"
+        />
+
     <FrameLayout
         android:id="@+id/bar_shadow_holder"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_area.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_area.xml
index 6e3b0d7..c25a51e 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_area.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_area.xml
@@ -41,6 +41,15 @@
             android:src="@drawable/ic_sysbar_ime_default"
             android:visibility="gone"
             />
+        
+        <com.android.systemui.statusbar.tablet.ShirtPocket
+            android:id="@+id/shirt_pocket"
+            android:layout_width="@*android:dimen/status_bar_height"
+            android:layout_height="@*android:dimen/status_bar_height"
+            android:background="#FFFF0000"
+            android:visibility="gone"
+            />
+
         <com.android.systemui.statusbar.tablet.NotificationIconArea
             android:id="@+id/notificationIcons"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index a67f915..ddb43b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -16,26 +16,28 @@
 
 package com.android.systemui.statusbar.tablet;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.util.Slog;
-import android.view.View;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.view.DragEvent;
-import android.view.MotionEvent;
 import android.content.ClipData;
 import android.content.ClipDescription;
-import android.graphics.Paint;
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Point;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.view.WindowManagerImpl;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.DragEvent;
 import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 
@@ -45,10 +47,80 @@
 
     private ClipData mClipping = null;
 
-    private View mWindow = null;
     private ImageView mPreviewIcon;
-    private TextView mDescription;
-    private TextView mAltText;
+
+    public static class DropZone extends View {
+        ShirtPocket mPocket;
+        public DropZone(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+        public void setPocket(ShirtPocket p) {
+            mPocket = p;
+        }
+
+        public void onAttachedToWindow() {
+            super.onAttachedToWindow();
+            if (mPocket.holding()) {
+                show(false);
+            } else {
+                hide(false);
+            }
+        }
+
+        // Drag API notes: we must be visible to receive drag events
+        private void show(boolean animate) {
+            setTranslationY(0f);
+            if (animate) {
+                setAlpha(0f);
+                ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).start();
+            } else {
+                setAlpha(1f);
+            }
+        }
+
+        private void hide(boolean animate) {
+            AnimatorListenerAdapter onEnd = new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator _a) {
+                    DropZone.this.setTranslationY(getHeight() + 2);
+                    DropZone.this.setAlpha(0f);
+                }
+            };
+            if (animate) {
+                Animator a = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 0f);
+                a.addListener(onEnd);
+                a.start();
+            } else {
+                onEnd.onAnimationEnd(null);
+            }
+        }
+
+        @Override
+        public boolean onDragEvent(DragEvent event) {
+            if (DEBUG) Slog.d(TAG, "onDragEvent: " + event);
+            switch (event.getAction()) {
+                // We want to appear whenever a potential drag takes off from anywhere in the UI.
+                case DragEvent.ACTION_DRAG_STARTED:
+                    show(true);
+                    break;
+                case DragEvent.ACTION_DRAG_ENTERED:
+                    if (DEBUG) Slog.d(TAG, "entered!");
+                    // XXX: TODO
+                    break;
+                case DragEvent.ACTION_DRAG_EXITED:
+                    if (DEBUG) Slog.d(TAG, "exited!");
+                    break;
+                case DragEvent.ACTION_DROP:
+                    if (DEBUG) Slog.d(TAG, "dropped!");
+                    mPocket.stash(event.getClipData());
+                    break;
+                case DragEvent.ACTION_DRAG_ENDED:
+                    hide(true);
+                    break;
+            }
+            return true; // we want everything, thank you
+        }
+    }
 
     public ShirtPocket(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -58,74 +130,66 @@
     ObjectAnimator mAnimHide, mAnimShow;
     
     protected void onAttachedToWindow() {
-        // Drag API notes: we must be visible to receive drag events
-        setVisibility(View.VISIBLE);
-
-        refresh();
-
-        setOnClickListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                if (mClipping != null) {
-                    if (mWindow.getVisibility() == View.VISIBLE) hideWindow(); 
-                    else showWindow();
-                }
-            }
-        });
     }
 
-    private void refresh() {
-        setClickable(mClipping != null);
-        // XXX: TODO
-    }
-    
-    private void showWindow() {
-        getHandler().post(new Runnable() {
-            public void run() {
-                mWindow.setVisibility(View.VISIBLE);
-                refresh();
-            }
-        });
-    }
-
-    private void hideWindow() {
-        getHandler().post(new Runnable() {
-            public void run() {
-                mWindow.setVisibility(View.GONE);
-                refresh();
-            }
-        });
-    }
-    
-    private void hideWindowInJustASec() {
-        getHandler().postDelayed(new Runnable() {
-            public void run() {
-                mWindow.setVisibility(View.GONE);
-                refresh();
-            }
-        },
-        250);
+    public boolean holding() {
+        return (mClipping != null);
     }
 
     private void stash(ClipData clipping) {
         mClipping = clipping;
         if (mClipping != null) {
+            setVisibility(View.VISIBLE);
             Bitmap icon = mClipping.getIcon();
-            mDescription.setText(mClipping.getDescription().getLabel());
+//            mDescription.setText(mClipping.getDescription().getLabel());
             if (icon != null) {
-                mPreviewIcon.setImageBitmap(icon);
-                mPreviewIcon.setVisibility(View.VISIBLE);
-                mAltText.setVisibility(View.GONE);
+                setImageBitmap(icon);
             } else {
-                mPreviewIcon.setVisibility(View.GONE);
-                mAltText.setVisibility(View.VISIBLE);
                 if (mClipping.getItemCount() > 0) {
                     // TODO: figure out how to visualize every kind of ClipData!
-                    mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext()));
+                    //mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext()));
                 }
             }
+        } else {
+            setVisibility(View.GONE);
         }
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+        if (action == MotionEvent.ACTION_DOWN) {
+            final ClipData clip = mClipping;
+            if (clip != null) {
+                final Bitmap icon = clip.getIcon();
+                DragShadowBuilder shadow;
+                if (icon != null) {
+                    shadow = new DragShadowBuilder(this) {
+                        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
+                            shadowSize.set(icon.getWidth(), icon.getHeight());
+                            shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
+                        }
+                        public void onDrawShadow(Canvas canvas) {
+                            canvas.drawBitmap(icon, 0, 0, new Paint());
+                        }
+                    };
+                } else {
+                    // uhhh, what now?
+                    shadow = new DragShadowBuilder(this);
+                }
+
+                startDrag(clip, shadow, null, 0);
+
+                // TODO: only discard the clipping if it was accepted
+                stash(null);
+
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /*
     private boolean isInViewContentArea(View v, int x, int y) {
         final int l = v.getPaddingLeft();
         final int r = v.getWidth() - v.getPaddingRight();
@@ -167,38 +231,12 @@
                     // TODO: only discard the clipping if it was accepted
                     stash(null);
 
-                    hideWindowInJustASec(); // will refresh the icon
-
                     return true;
                 }
             }
             return false;
         }
     };
-
-    public boolean onDragEvent(DragEvent event) {
-        if (DEBUG) Slog.d(TAG, "onDragEvent: " + event);
-        switch (event.getAction()) {
-            // We want to appear whenever a potential drag takes off from anywhere in the UI.
-            case DragEvent.ACTION_DRAG_STARTED:
-                // XXX: TODO
-                break;
-            case DragEvent.ACTION_DRAG_ENTERED:
-                if (DEBUG) Slog.d(TAG, "entered!");
-                // XXX: TODO
-                break;
-            case DragEvent.ACTION_DRAG_EXITED:
-                if (DEBUG) Slog.d(TAG, "exited!");
-                setVisibility(mClipping == null ? View.GONE : View.VISIBLE);
-                break;
-            case DragEvent.ACTION_DROP:
-                if (DEBUG) Slog.d(TAG, "dropped!");
-                stash(event.getClipData());
-                break;
-            case DragEvent.ACTION_DRAG_ENDED:
-                break;
-        }
-        return true; // we want everything, thank you
-    }
+    */
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 7a13fde..bb0d3e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -392,6 +392,11 @@
         // for redirecting errant bar taps to the IME
         mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar);
 
+        // drag and drop pocket
+        ShirtPocket p = (ShirtPocket) sb.findViewById(R.id.shirt_pocket);
+        ShirtPocket.DropZone z = (ShirtPocket.DropZone) sb.findViewById(R.id.drop_target);
+        z.setPocket(p);
+
         // "shadows" of the status bar features, for lights-out mode
         mShadow = sb.findViewById(R.id.bar_shadow);
         mShadow.setOnTouchListener(