UI Android

/*
 * Copyright (C) 2010 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.
 */
package com.example.android.apis.view;
import com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.View;
import android.widget.TextView;
import android.content.ClipData;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.os.SystemClock;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.View;
import android.widget.TextView;
 class DraggableDot extends View {
    static final String TAG = "DraggableDot";
    private boolean mDragInProgress;
    private boolean mHovering;
    private boolean mAcceptsDrag;
    TextView mReportView;
    private Paint mPaint;
    private TextPaint mLegendPaint;
    private Paint mGlow;
    private static final int NUM_GLOW_STEPS = 10;
    private static final int GREEN_STEP = 0x0000FF00 / NUM_GLOW_STEPS;
    private static final int WHITE_STEP = 0x00FFFFFF / NUM_GLOW_STEPS;
    private static final int ALPHA_STEP = 0xFF000000 / NUM_GLOW_STEPS;
    int mRadius;
    int mAnrType;
    CharSequence mLegend;
    static final int ANR_NONE = 0;
    static final int ANR_SHADOW = 1;
    static final int ANR_DROP = 2;
    void sleepSixSeconds() {
        // hang forever; good for producing ANRs
        long start = SystemClock.uptimeMillis();
        do {
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
        } while (SystemClock.uptimeMillis() < start + 6000);
    }
    // Shadow builder that can ANR if desired
    class ANRShadowBuilder extends DragShadowBuilder {
        boolean mDoAnr;
        public ANRShadowBuilder(View view, boolean doAnr) {
            super(view);
            mDoAnr = doAnr;
        }
        @Override
        public void onDrawShadow(Canvas canvas) {
            if (mDoAnr) {
                sleepSixSeconds();
            }
            super.onDrawShadow(canvas);
        }
    }
    public DraggableDot(Context context, AttributeSet attrs) {
        super(context, attrs);
        setFocusable(true);
        setClickable(true);
        mLegend = "";
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(6);
        mPaint.setColor(0xFFD00000);
        mLegendPaint = new TextPaint();
        mLegendPaint.setAntiAlias(true);
        mLegendPaint.setTextAlign(Paint.Align.CENTER);
        mLegendPaint.setColor(0xFFF0F0FF);
        mGlow = new Paint();
        mGlow.setAntiAlias(true);
        mGlow.setStrokeWidth(1);
        mGlow.setStyle(Paint.Style.STROKE);
        // look up any layout-defined attributes
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.DraggableDot);
        final int N = a.getIndexCount();
        for (int i = 0; i < N; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
            case R.styleable.DraggableDot_radius: {
                mRadius = a.getDimensionPixelSize(attr, 0);
            } break;
            case R.styleable.DraggableDot_legend: {
                mLegend = a.getText(attr);
            } break;
            case R.styleable.DraggableDot_anr: {
                mAnrType = a.getInt(attr, 0);
            } break;
            }
        }
        Log.i(TAG, "DraggableDot @ " + this + " : radius=" + mRadius + " legend='" + mLegend
                + "' anr=" + mAnrType);
        setOnLongClickListener(new View.OnLongClickListener() {
            public boolean onLongClick(View v) {
                ClipData data = ClipData.newPlainText("dot", "Dot : " + v.toString());
                v.startDrag(data, new ANRShadowBuilder(v, mAnrType == ANR_SHADOW),
                        (Object)v, 0);
                return true;
            }
        });
    }
    void setReportView(TextView view) {
        mReportView = view;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        float wf = getWidth();
        float hf = getHeight();
        final float cx = wf/2;
        final float cy = hf/2;
        wf -= getPaddingLeft() + getPaddingRight();
        hf -= getPaddingTop() + getPaddingBottom();
        float rad = (wf < hf) ? wf/2 : hf/2;
        canvas.drawCircle(cx, cy, rad, mPaint);
        if (mLegend != null && mLegend.length() > 0) {
            canvas.drawText(mLegend, 0, mLegend.length(),
                    cx, cy + mLegendPaint.getFontSpacing()/2,
                    mLegendPaint);
        }
        // if we're in the middle of a drag, light up as a potential target
        if (mDragInProgress && mAcceptsDrag) {
            for (int i = NUM_GLOW_STEPS; i > 0; i--) {
                int color = (mHovering) ? WHITE_STEP : GREEN_STEP;
                color = i*(color | ALPHA_STEP);
                mGlow.setColor(color);
                canvas.drawCircle(cx, cy, rad, mGlow);
                rad -= 0.5f;
                canvas.drawCircle(cx, cy, rad, mGlow);
                rad -= 0.5f;
            }
        }
    }
    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        int totalDiameter = 2*mRadius + getPaddingLeft() + getPaddingRight();
        setMeasuredDimension(totalDiameter, totalDiameter);
    }
    /**
     * Drag and drop
     */
    @Override
    public boolean onDragEvent(DragEvent event) {
        boolean result = false;
        switch (event.getAction()) {
        case DragEvent.ACTION_DRAG_STARTED: {
            // claim to accept any dragged content
            Log.i(TAG, "Drag started, event=" + event);
            // cache whether we accept the drag to return for LOCATION events
            mDragInProgress = true;
            mAcceptsDrag = result = true;
            // Redraw in the new visual state if we are a potential drop target
            if (mAcceptsDrag) {
                invalidate();
            }
        } break;
        case DragEvent.ACTION_DRAG_ENDED: {
            Log.i(TAG, "Drag ended.");
            if (mAcceptsDrag) {
                invalidate();
            }
            mDragInProgress = false;
            mHovering = false;
        } break;
        case DragEvent.ACTION_DRAG_LOCATION: {
            // we returned true to DRAG_STARTED, so return true here
            Log.i(TAG, "... seeing drag locations ...");
            result = mAcceptsDrag;
        } break;
        case DragEvent.ACTION_DROP: {
            Log.i(TAG, "Got a drop! dot=" + this + " event=" + event);
            if (mAnrType == ANR_DROP) {
                sleepSixSeconds();
            }
            processDrop(event);
            result = true;
        } break;
        case DragEvent.ACTION_DRAG_ENTERED: {
            Log.i(TAG, "Entered dot @ " + this);
            mHovering = true;
            invalidate();
        } break;
        case DragEvent.ACTION_DRAG_EXITED: {
            Log.i(TAG, "Exited dot @ " + this);
            mHovering = false;
            invalidate();
        } break;
        default:
            Log.i(TAG, "other drag event: " + event);
            result = mAcceptsDrag;
            break;
        }
        return result;
    }
    private void processDrop(DragEvent event) {
        final ClipData data = event.getClipData();
        final int N = data.getItemCount();
        for (int i = 0; i < N; i++) {
            ClipData.Item item = data.getItemAt(i);
            Log.i(TAG, "Dropped item " + i + " : " + item);
            if (mReportView != null) {
                String text = item.coerceToText(getContext()).toString();
                if (event.getLocalState() == (Object) this) {
                    text += " : Dropped on self!";
                }
                mReportView.setText(text);
            }
        }
    }
}
public class Test extends Activity {
    TextView mResultText;
    DraggableDot mHiddenDot;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView text = (TextView) findViewById(R.id.drag_text);
        DraggableDot dot = (DraggableDot) findViewById(R.id.drag_dot_1);
        dot.setReportView(text);
        dot = (DraggableDot) findViewById(R.id.drag_dot_2);
        dot.setReportView(text);
        dot = (DraggableDot) findViewById(R.id.drag_dot_3);
        dot.setReportView(text);
        mHiddenDot = (DraggableDot) findViewById(R.id.drag_dot_hidden);
        mHiddenDot.setReportView(text);
        mResultText = (TextView) findViewById(R.id.drag_result_text);
        mResultText.setOnDragListener(new View.OnDragListener() {
            public boolean onDrag(View v, DragEvent event) {
                final int action = event.getAction();
                switch (action) {
                    case DragEvent.ACTION_DRAG_STARTED: {
                        // Bring up a fourth draggable dot on the fly. Note that it
                        // is properly notified about the ongoing drag, and lights up
                        // to indicate that it can handle the current content.
                        mHiddenDot.setVisibility(View.VISIBLE);
                    } break;
                    case DragEvent.ACTION_DRAG_ENDED: {
                        // Hide the surprise again
                        mHiddenDot.setVisibility(View.INVISIBLE);
                        // Report the drop/no-drop result to the user
                        final boolean dropped = event.getResult();
                        mResultText.setText(dropped ? "Dropped!" : "No drop");
                    } break;
                }
                return false;
            }
        });
    }
}
//main.xml



    xmlns:dot="http://schemas.android.com/apk/res/com.example.android.apis"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >
            android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="drag_explanation"
        />
            android:id="@+id/drag_dot_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        dot:radius="64dp"
        android:padding="15dp"
        android:layout_below="@id/drag_explanation"
        />
            android:id="@+id/drag_dot_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        dot:radius="64dp"
        android:padding="15dp"
        android:layout_below="@id/drag_explanation"
        android:layout_toRightOf="@id/drag_dot_1"
        dot:legend="Drag ANR"
        dot:anr="thumbnail"
        />
            android:id="@+id/drag_dot_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        dot:radius="64dp"
        android:padding="15dp"
        android:layout_below="@id/drag_dot_1"
        android:layout_alignLeft="@id/drag_dot_1"
        dot:legend="Drop ANR"
        dot:anr="drop"
        />
            android:id="@+id/drag_dot_hidden"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        dot:radius="64dp"
        android:padding="15dp"
        android:layout_toRightOf="@id/drag_dot_3"
        android:layout_alignTop="@id/drag_dot_3"
        android:visibility="invisible"
        dot:legend="Surprise!"
        />
            android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/drag_explanation"
        android:layout_alignRight="@id/drag_explanation"
        android:layout_toRightOf="@id/drag_dot_2"
        />
            android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:layout_below="@id/drag_dot_3"
        android:layout_alignLeft="@id/drag_dot_3"
        />