ShirtPocket.java revision 98365d7663cbd82979a5700faf0050220b01084d
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.tablet;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ObjectAnimator;
22import android.content.ClipData;
23import android.content.ClipDescription;
24import android.content.Context;
25import android.graphics.Bitmap;
26import android.graphics.Canvas;
27import android.graphics.Paint;
28import android.graphics.PixelFormat;
29import android.graphics.Point;
30import android.util.AttributeSet;
31import android.util.Slog;
32import android.view.DragEvent;
33import android.view.Gravity;
34import android.view.MotionEvent;
35import android.view.View;
36import android.view.WindowManager;
37import android.widget.FrameLayout;
38import android.widget.ImageView;
39import android.widget.TextView;
40
41import com.android.systemui.R;
42
43public class ShirtPocket extends ImageView {
44    private static final boolean DEBUG = false;
45    private static final String  TAG = "StatusBar/ShirtPocket";
46
47    private ClipData mClipping = null;
48
49    private ImageView mPreviewIcon;
50
51    public static class DropZone extends View {
52        ShirtPocket mPocket;
53        public DropZone(Context context, AttributeSet attrs) {
54            super(context, attrs);
55        }
56        public void setPocket(ShirtPocket p) {
57            mPocket = p;
58        }
59
60        public void onAttachedToWindow() {
61            super.onAttachedToWindow();
62            if (mPocket.holding()) {
63                show(false);
64            } else {
65                hide(false);
66            }
67        }
68
69        // Drag API notes: we must be visible to receive drag events
70        private void show(boolean animate) {
71            setTranslationY(0f);
72            if (animate) {
73                setAlpha(0f);
74                ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).start();
75            } else {
76                setAlpha(1f);
77            }
78        }
79
80        private void hide(boolean animate) {
81            AnimatorListenerAdapter onEnd = new AnimatorListenerAdapter() {
82                @Override
83                public void onAnimationEnd(Animator _a) {
84                    DropZone.this.setTranslationY(getHeight() + 2);
85                    DropZone.this.setAlpha(0f);
86                }
87            };
88            if (animate) {
89                Animator a = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 0f);
90                a.addListener(onEnd);
91                a.start();
92            } else {
93                onEnd.onAnimationEnd(null);
94            }
95        }
96
97        @Override
98        public boolean onDragEvent(DragEvent event) {
99            if (DEBUG) Slog.d(TAG, "onDragEvent: " + event);
100            switch (event.getAction()) {
101                // We want to appear whenever a potential drag takes off from anywhere in the UI.
102                case DragEvent.ACTION_DRAG_STARTED:
103                    show(true);
104                    break;
105                case DragEvent.ACTION_DRAG_ENTERED:
106                    if (DEBUG) Slog.d(TAG, "entered!");
107                    // XXX: TODO
108                    break;
109                case DragEvent.ACTION_DRAG_EXITED:
110                    if (DEBUG) Slog.d(TAG, "exited!");
111                    break;
112                case DragEvent.ACTION_DROP:
113                    if (DEBUG) Slog.d(TAG, "dropped!");
114                    mPocket.stash(event.getClipData());
115                    break;
116                case DragEvent.ACTION_DRAG_ENDED:
117                    hide(true);
118                    break;
119            }
120            return true; // we want everything, thank you
121        }
122    }
123
124    public ShirtPocket(Context context, AttributeSet attrs) {
125        super(context, attrs);
126    }
127
128    // TODO: "pin area" panel, dragging things out
129    ObjectAnimator mAnimHide, mAnimShow;
130
131    protected void onAttachedToWindow() {
132    }
133
134    public boolean holding() {
135        return (mClipping != null);
136    }
137
138    private void stash(ClipData clipping) {
139        mClipping = clipping;
140        if (mClipping != null) {
141            setVisibility(View.VISIBLE);
142            Bitmap icon = mClipping.getIcon();
143//            mDescription.setText(mClipping.getDescription().getLabel());
144            if (icon != null) {
145                setImageBitmap(icon);
146            } else {
147                if (mClipping.getItemCount() > 0) {
148                    // TODO: figure out how to visualize every kind of ClipData!
149                    //mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext()));
150                }
151            }
152        } else {
153            setVisibility(View.GONE);
154        }
155    }
156
157    @Override
158    public boolean onTouchEvent(MotionEvent ev) {
159        final int action = ev.getAction();
160        if (action == MotionEvent.ACTION_DOWN) {
161            final ClipData clip = mClipping;
162            if (clip != null) {
163                final Bitmap icon = clip.getIcon();
164                DragShadowBuilder shadow;
165                if (icon != null) {
166                    shadow = new DragShadowBuilder(this) {
167                        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
168                            shadowSize.set(icon.getWidth(), icon.getHeight());
169                            shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
170                        }
171                        public void onDrawShadow(Canvas canvas) {
172                            canvas.drawBitmap(icon, 0, 0, new Paint());
173                        }
174                    };
175                } else {
176                    // uhhh, what now?
177                    shadow = new DragShadowBuilder(this);
178                }
179
180                startDrag(clip, shadow, null, 0);
181
182                // TODO: only discard the clipping if it was accepted
183                stash(null);
184
185                return true;
186            }
187        }
188        return false;
189    }
190
191    /*
192    private boolean isInViewContentArea(View v, int x, int y) {
193        final int l = v.getPaddingLeft();
194        final int r = v.getWidth() - v.getPaddingRight();
195        final int t = v.getPaddingTop();
196        final int b = v.getHeight() - v.getPaddingBottom();
197        return x >= l && x < r && y >= t && y < b;
198    }
199
200    View.OnTouchListener mWindowTouchListener = new View.OnTouchListener() {
201        public boolean onTouch(View v, MotionEvent ev) {
202            final int action = ev.getAction();
203            if (action == MotionEvent.ACTION_OUTSIDE
204                    || (action == MotionEvent.ACTION_DOWN
205                        && !isInViewContentArea(mWindow, (int)ev.getX(), (int)ev.getY()))) {
206                hideWindow();
207                return true;
208            } else if (action == MotionEvent.ACTION_DOWN) {
209                final ClipData clip = mClipping;
210                if (clip != null) {
211                    final Bitmap icon = clip.getIcon();
212                    DragShadowBuilder shadow;
213                    if (icon != null) {
214                        shadow = new DragShadowBuilder(v) {
215                            public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
216                                shadowSize.set(icon.getWidth(), icon.getHeight());
217                                shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
218                            }
219                            public void onDrawShadow(Canvas canvas) {
220                                canvas.drawBitmap(icon, 0, 0, new Paint());
221                            }
222                        };
223                    } else {
224                        // uhhh, what now?
225                        shadow = new DragShadowBuilder(mWindow.findViewById(R.id.preview));
226                    }
227
228                    v.startDrag(clip, shadow, null, 0);
229
230                    // TODO: only discard the clipping if it was accepted
231                    stash(null);
232
233                    return true;
234                }
235            }
236            return false;
237        }
238    };
239    */
240}
241
242