ShirtPocket.java revision 0ad460b087abbd4b523a2e61ff27b0bf6fb5be92
1524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler/*
2524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * Copyright (C) 2010 The Android Open Source Project
3524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler *
4524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
5524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * you may not use this file except in compliance with the License.
6524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * You may obtain a copy of the License at
7524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler *
8524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
9524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler *
10524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * Unless required by applicable law or agreed to in writing, software
11524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
12524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * See the License for the specific language governing permissions and
14524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler * limitations under the License.
15524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler */
16524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
17524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerpackage com.android.systemui.statusbar.tablet;
18524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
19524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.animation.ObjectAnimator;
20524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.content.Context;
21524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.util.Slog;
22524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.view.View;
23524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.util.AttributeSet;
24524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.widget.ImageView;
25524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.widget.TextView;
26524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.view.DragEvent;
27524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.view.MotionEvent;
28524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.content.ClipData;
29524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.content.ClipDescription;
30524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.graphics.Paint;
31524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.graphics.Bitmap;
32524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.graphics.Canvas;
33524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.graphics.Point;
34524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.view.WindowManager;
35524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.widget.FrameLayout;
36524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.view.WindowManagerImpl;
37524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.graphics.PixelFormat;
38524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport android.view.Gravity;
39524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
40524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandlerimport com.android.systemui.R;
41524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
420ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandlerpublic class ShirtPocket extends ImageView {
43524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private static final boolean DEBUG = false;
44524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private static final String  TAG = "StatusBar/ShirtPocket";
45524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
46524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private ClipData mClipping = null;
47524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
48524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private View mWindow = null;
49524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private ImageView mPreviewIcon;
50524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private TextView mDescription;
51524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private TextView mAltText;
52524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
53524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    public ShirtPocket(Context context, AttributeSet attrs) {
54524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        super(context, attrs);
55524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
56524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
57524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    // TODO: "pin area" panel, dragging things out
58524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    ObjectAnimator mAnimHide, mAnimShow;
59524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
60524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    protected void onAttachedToWindow() {
61524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        // Drag API notes: we must be visible to receive drag events
62524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        setVisibility(View.VISIBLE);
63524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
640ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler        refresh();
65524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
66524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        setOnClickListener(new View.OnClickListener() {
67524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            public void onClick(View v) {
68524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                if (mClipping != null) {
69524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    if (mWindow.getVisibility() == View.VISIBLE) hideWindow();
70524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    else showWindow();
71524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                }
72524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            }
73524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        });
74524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
75524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
760ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler    private void refresh() {
77524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        setClickable(mClipping != null);
780ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler        // XXX: TODO
79524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
80524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
81524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private void showWindow() {
82524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        getHandler().post(new Runnable() {
83524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            public void run() {
84524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mWindow.setVisibility(View.VISIBLE);
850ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                refresh();
86524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            }
87524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        });
88524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
89524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
90524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private void hideWindow() {
91524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        getHandler().post(new Runnable() {
92524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            public void run() {
93524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mWindow.setVisibility(View.GONE);
940ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                refresh();
95524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            }
96524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        });
97524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
98524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
99524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private void hideWindowInJustASec() {
100524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        getHandler().postDelayed(new Runnable() {
101524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            public void run() {
102524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mWindow.setVisibility(View.GONE);
1030ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                refresh();
104524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            }
105524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        },
106524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        250);
107524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
108524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
109524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private void stash(ClipData clipping) {
110524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        mClipping = clipping;
111524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        if (mClipping != null) {
112524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            Bitmap icon = mClipping.getIcon();
113f834dfabbcbbe1f209682f18c67f2e8b9d3e1dd7Dianne Hackborn            mDescription.setText(mClipping.getDescription().getLabel());
114524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            if (icon != null) {
115524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mPreviewIcon.setImageBitmap(icon);
116524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mPreviewIcon.setVisibility(View.VISIBLE);
117524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mAltText.setVisibility(View.GONE);
118524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            } else {
119524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mPreviewIcon.setVisibility(View.GONE);
120524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                mAltText.setVisibility(View.VISIBLE);
121524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                if (mClipping.getItemCount() > 0) {
122524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    // TODO: figure out how to visualize every kind of ClipData!
123524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    mAltText.setText(mClipping.getItem(0).coerceToText(getContext()));
124524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                }
125524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            }
126524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        }
127524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
128524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
129524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    private boolean isInViewContentArea(View v, int x, int y) {
130524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        final int l = v.getPaddingLeft();
131524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        final int r = v.getWidth() - v.getPaddingRight();
132524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        final int t = v.getPaddingTop();
133524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        final int b = v.getHeight() - v.getPaddingBottom();
134524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        return x >= l && x < r && y >= t && y < b;
135524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
136524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
137524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    View.OnTouchListener mWindowTouchListener = new View.OnTouchListener() {
138524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        public boolean onTouch(View v, MotionEvent ev) {
139524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            final int action = ev.getAction();
140524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            if (action == MotionEvent.ACTION_OUTSIDE
141524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    || (action == MotionEvent.ACTION_DOWN
142524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                        && !isInViewContentArea(mWindow, (int)ev.getX(), (int)ev.getY()))) {
143524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                hideWindow();
144524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                return true;
145524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            } else if (action == MotionEvent.ACTION_DOWN) {
146524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                Slog.d(TAG, "ACTION_DOWN");
147524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                final ClipData clip = mClipping;
148524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                if (clip != null) {
149524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    final Bitmap icon = clip.getIcon();
150524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    DragThumbnailBuilder thumb;
151524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    if (icon != null) {
152524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                        thumb = new DragThumbnailBuilder(v) {
153524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                            public void onProvideThumbnailMetrics(Point thumbnailSize, Point thumbnailTouchPoint) {
154524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                                thumbnailSize.set(icon.getWidth(), icon.getHeight());
155524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                                thumbnailTouchPoint.set(thumbnailSize.x / 2, thumbnailSize.y / 2);
156524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                            }
157524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                            public void onDrawThumbnail(Canvas canvas) {
158524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                                canvas.drawBitmap(icon, 0, 0, new Paint());
159524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                            }
160524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                        };
161524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    } else {
162524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                        // uhhh, what now?
163524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                        thumb = new DragThumbnailBuilder(mWindow.findViewById(R.id.preview));
164524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    }
165524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
166407b4e91fe7627545b8110e683953353236b4543Christopher Tate                    v.startDrag(clip, thumb, false, null);
167524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
168524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    // TODO: only discard the clipping if it was accepted
169524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    stash(null);
170524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
171524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    hideWindowInJustASec(); // will refresh the icon
172524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
173524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                    return true;
174524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler                }
175524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            }
176524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler            return false;
177524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        }
178524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    };
179524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
180524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    public boolean onDragEvent(DragEvent event) {
181524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        if (DEBUG) Slog.d(TAG, "onDragEvent: " + event);
1820ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler        switch (event.getAction()) {
1830ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler            // We want to appear whenever a potential drag takes off from anywhere in the UI.
1840ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler            case DragEvent.ACTION_DRAG_STARTED:
1850ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                // XXX: TODO
1860ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                break;
1870ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler            case DragEvent.ACTION_DRAG_ENTERED:
1880ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                if (DEBUG) Slog.d(TAG, "entered!");
1890ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                // XXX: TODO
1900ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                break;
1910ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler            case DragEvent.ACTION_DRAG_EXITED:
1920ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                if (DEBUG) Slog.d(TAG, "exited!");
1930ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                setVisibility(mClipping == null ? View.GONE : View.VISIBLE);
1940ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                break;
1950ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler            case DragEvent.ACTION_DROP:
1960ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                if (DEBUG) Slog.d(TAG, "dropped!");
1970ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                stash(event.getClipData());
1980ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                break;
1990ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler            case DragEvent.ACTION_DRAG_ENDED:
2000ad460b087abbd4b523a2e61ff27b0bf6fb5be92Daniel Sandler                break;
201524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        }
202524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler        return true; // we want everything, thank you
203524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler    }
204524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler}
205524f568802c32ba1126fe2886f3e96d018d7f23dDaniel Sandler
206