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