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