Loading packages/SystemUI/res/drawable-mdpi/pocket_drag_pattern.png 0 → 100644 +324 B Loading image diff... packages/SystemUI/res/drawable/pocket_drag_bg.xml 0 → 100644 +21 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2011 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. --> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:tileMode="repeat" android:src="@drawable/pocket_drag_pattern" /> packages/SystemUI/res/layout-xlarge/status_bar.xml +9 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,15 @@ </RelativeLayout> </FrameLayout> <view class="com.android.systemui.statusbar.tablet.ShirtPocket$DropZone" android:id="@+id/drop_target" android:layout_width="512dp" android:layout_height="@*android:dimen/status_bar_height" android:background="@drawable/pocket_drag_bg" android:layout_gravity="right" /> <FrameLayout android:id="@+id/bar_shadow_holder" android:layout_width="match_parent" Loading packages/SystemUI/res/layout-xlarge/status_bar_notification_area.xml +9 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,15 @@ android:src="@drawable/ic_sysbar_ime_default" android:visibility="gone" /> <com.android.systemui.statusbar.tablet.ShirtPocket android:id="@+id/shirt_pocket" android:layout_width="@*android:dimen/status_bar_height" android:layout_height="@*android:dimen/status_bar_height" android:background="#FFFF0000" android:visibility="gone" /> <com.android.systemui.statusbar.tablet.NotificationIconArea android:id="@+id/notificationIcons" android:layout_width="wrap_content" Loading packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java +130 −92 Original line number Diff line number Diff line Loading @@ -16,26 +16,28 @@ package com.android.systemui.statusbar.tablet; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.util.Slog; import android.view.View; import android.util.AttributeSet; import android.widget.ImageView; import android.widget.TextView; import android.view.DragEvent; import android.view.MotionEvent; import android.content.ClipData; import android.content.ClipDescription; import android.graphics.Paint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.util.AttributeSet; import android.util.Slog; import android.view.DragEvent; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; import android.view.WindowManagerImpl; import android.graphics.PixelFormat; import android.view.Gravity; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import com.android.systemui.R; Loading @@ -45,87 +47,149 @@ public class ShirtPocket extends ImageView { private ClipData mClipping = null; private View mWindow = null; private ImageView mPreviewIcon; private TextView mDescription; private TextView mAltText; public ShirtPocket(Context context, AttributeSet attrs) { public static class DropZone extends View { ShirtPocket mPocket; public DropZone(Context context, AttributeSet attrs) { super(context, attrs); } public void setPocket(ShirtPocket p) { mPocket = p; } // TODO: "pin area" panel, dragging things out ObjectAnimator mAnimHide, mAnimShow; public void onAttachedToWindow() { super.onAttachedToWindow(); if (mPocket.holding()) { show(false); } else { hide(false); } } protected void onAttachedToWindow() { // Drag API notes: we must be visible to receive drag events setVisibility(View.VISIBLE); refresh(); private void show(boolean animate) { setTranslationY(0f); if (animate) { setAlpha(0f); ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).start(); } else { setAlpha(1f); } } setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (mClipping != null) { if (mWindow.getVisibility() == View.VISIBLE) hideWindow(); else showWindow(); private void hide(boolean animate) { AnimatorListenerAdapter onEnd = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator _a) { DropZone.this.setTranslationY(getHeight() + 2); DropZone.this.setAlpha(0f); } }; if (animate) { Animator a = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 0f); a.addListener(onEnd); a.start(); } else { onEnd.onAnimationEnd(null); } }); } private void refresh() { setClickable(mClipping != null); @Override public boolean onDragEvent(DragEvent event) { if (DEBUG) Slog.d(TAG, "onDragEvent: " + event); switch (event.getAction()) { // We want to appear whenever a potential drag takes off from anywhere in the UI. case DragEvent.ACTION_DRAG_STARTED: show(true); break; case DragEvent.ACTION_DRAG_ENTERED: if (DEBUG) Slog.d(TAG, "entered!"); // XXX: TODO break; case DragEvent.ACTION_DRAG_EXITED: if (DEBUG) Slog.d(TAG, "exited!"); break; case DragEvent.ACTION_DROP: if (DEBUG) Slog.d(TAG, "dropped!"); mPocket.stash(event.getClipData()); break; case DragEvent.ACTION_DRAG_ENDED: hide(true); break; } private void showWindow() { getHandler().post(new Runnable() { public void run() { mWindow.setVisibility(View.VISIBLE); refresh(); return true; // we want everything, thank you } }); } private void hideWindow() { getHandler().post(new Runnable() { public void run() { mWindow.setVisibility(View.GONE); refresh(); } }); public ShirtPocket(Context context, AttributeSet attrs) { super(context, attrs); } private void hideWindowInJustASec() { getHandler().postDelayed(new Runnable() { public void run() { mWindow.setVisibility(View.GONE); refresh(); // TODO: "pin area" panel, dragging things out ObjectAnimator mAnimHide, mAnimShow; protected void onAttachedToWindow() { } }, 250); public boolean holding() { return (mClipping != null); } private void stash(ClipData clipping) { mClipping = clipping; if (mClipping != null) { setVisibility(View.VISIBLE); Bitmap icon = mClipping.getIcon(); mDescription.setText(mClipping.getDescription().getLabel()); // mDescription.setText(mClipping.getDescription().getLabel()); if (icon != null) { mPreviewIcon.setImageBitmap(icon); mPreviewIcon.setVisibility(View.VISIBLE); mAltText.setVisibility(View.GONE); setImageBitmap(icon); } else { mPreviewIcon.setVisibility(View.GONE); mAltText.setVisibility(View.VISIBLE); if (mClipping.getItemCount() > 0) { // TODO: figure out how to visualize every kind of ClipData! mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext())); //mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext())); } } } else { setVisibility(View.GONE); } } @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); if (action == MotionEvent.ACTION_DOWN) { final ClipData clip = mClipping; if (clip != null) { final Bitmap icon = clip.getIcon(); DragShadowBuilder shadow; if (icon != null) { shadow = new DragShadowBuilder(this) { public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { shadowSize.set(icon.getWidth(), icon.getHeight()); shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2); } public void onDrawShadow(Canvas canvas) { canvas.drawBitmap(icon, 0, 0, new Paint()); } }; } else { // uhhh, what now? shadow = new DragShadowBuilder(this); } startDrag(clip, shadow, null, 0); // TODO: only discard the clipping if it was accepted stash(null); return true; } } return false; } /* private boolean isInViewContentArea(View v, int x, int y) { final int l = v.getPaddingLeft(); final int r = v.getWidth() - v.getPaddingRight(); Loading Loading @@ -167,38 +231,12 @@ public class ShirtPocket extends ImageView { // TODO: only discard the clipping if it was accepted stash(null); hideWindowInJustASec(); // will refresh the icon return true; } } return false; } }; public boolean onDragEvent(DragEvent event) { if (DEBUG) Slog.d(TAG, "onDragEvent: " + event); switch (event.getAction()) { // We want to appear whenever a potential drag takes off from anywhere in the UI. case DragEvent.ACTION_DRAG_STARTED: // XXX: TODO break; case DragEvent.ACTION_DRAG_ENTERED: if (DEBUG) Slog.d(TAG, "entered!"); // XXX: TODO break; case DragEvent.ACTION_DRAG_EXITED: if (DEBUG) Slog.d(TAG, "exited!"); setVisibility(mClipping == null ? View.GONE : View.VISIBLE); break; case DragEvent.ACTION_DROP: if (DEBUG) Slog.d(TAG, "dropped!"); stash(event.getClipData()); break; case DragEvent.ACTION_DRAG_ENDED: break; } return true; // we want everything, thank you } */ } Loading
packages/SystemUI/res/drawable/pocket_drag_bg.xml 0 → 100644 +21 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2011 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. --> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:tileMode="repeat" android:src="@drawable/pocket_drag_pattern" />
packages/SystemUI/res/layout-xlarge/status_bar.xml +9 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,15 @@ </RelativeLayout> </FrameLayout> <view class="com.android.systemui.statusbar.tablet.ShirtPocket$DropZone" android:id="@+id/drop_target" android:layout_width="512dp" android:layout_height="@*android:dimen/status_bar_height" android:background="@drawable/pocket_drag_bg" android:layout_gravity="right" /> <FrameLayout android:id="@+id/bar_shadow_holder" android:layout_width="match_parent" Loading
packages/SystemUI/res/layout-xlarge/status_bar_notification_area.xml +9 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,15 @@ android:src="@drawable/ic_sysbar_ime_default" android:visibility="gone" /> <com.android.systemui.statusbar.tablet.ShirtPocket android:id="@+id/shirt_pocket" android:layout_width="@*android:dimen/status_bar_height" android:layout_height="@*android:dimen/status_bar_height" android:background="#FFFF0000" android:visibility="gone" /> <com.android.systemui.statusbar.tablet.NotificationIconArea android:id="@+id/notificationIcons" android:layout_width="wrap_content" Loading
packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java +130 −92 Original line number Diff line number Diff line Loading @@ -16,26 +16,28 @@ package com.android.systemui.statusbar.tablet; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.util.Slog; import android.view.View; import android.util.AttributeSet; import android.widget.ImageView; import android.widget.TextView; import android.view.DragEvent; import android.view.MotionEvent; import android.content.ClipData; import android.content.ClipDescription; import android.graphics.Paint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.util.AttributeSet; import android.util.Slog; import android.view.DragEvent; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; import android.view.WindowManagerImpl; import android.graphics.PixelFormat; import android.view.Gravity; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import com.android.systemui.R; Loading @@ -45,87 +47,149 @@ public class ShirtPocket extends ImageView { private ClipData mClipping = null; private View mWindow = null; private ImageView mPreviewIcon; private TextView mDescription; private TextView mAltText; public ShirtPocket(Context context, AttributeSet attrs) { public static class DropZone extends View { ShirtPocket mPocket; public DropZone(Context context, AttributeSet attrs) { super(context, attrs); } public void setPocket(ShirtPocket p) { mPocket = p; } // TODO: "pin area" panel, dragging things out ObjectAnimator mAnimHide, mAnimShow; public void onAttachedToWindow() { super.onAttachedToWindow(); if (mPocket.holding()) { show(false); } else { hide(false); } } protected void onAttachedToWindow() { // Drag API notes: we must be visible to receive drag events setVisibility(View.VISIBLE); refresh(); private void show(boolean animate) { setTranslationY(0f); if (animate) { setAlpha(0f); ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).start(); } else { setAlpha(1f); } } setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (mClipping != null) { if (mWindow.getVisibility() == View.VISIBLE) hideWindow(); else showWindow(); private void hide(boolean animate) { AnimatorListenerAdapter onEnd = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator _a) { DropZone.this.setTranslationY(getHeight() + 2); DropZone.this.setAlpha(0f); } }; if (animate) { Animator a = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 0f); a.addListener(onEnd); a.start(); } else { onEnd.onAnimationEnd(null); } }); } private void refresh() { setClickable(mClipping != null); @Override public boolean onDragEvent(DragEvent event) { if (DEBUG) Slog.d(TAG, "onDragEvent: " + event); switch (event.getAction()) { // We want to appear whenever a potential drag takes off from anywhere in the UI. case DragEvent.ACTION_DRAG_STARTED: show(true); break; case DragEvent.ACTION_DRAG_ENTERED: if (DEBUG) Slog.d(TAG, "entered!"); // XXX: TODO break; case DragEvent.ACTION_DRAG_EXITED: if (DEBUG) Slog.d(TAG, "exited!"); break; case DragEvent.ACTION_DROP: if (DEBUG) Slog.d(TAG, "dropped!"); mPocket.stash(event.getClipData()); break; case DragEvent.ACTION_DRAG_ENDED: hide(true); break; } private void showWindow() { getHandler().post(new Runnable() { public void run() { mWindow.setVisibility(View.VISIBLE); refresh(); return true; // we want everything, thank you } }); } private void hideWindow() { getHandler().post(new Runnable() { public void run() { mWindow.setVisibility(View.GONE); refresh(); } }); public ShirtPocket(Context context, AttributeSet attrs) { super(context, attrs); } private void hideWindowInJustASec() { getHandler().postDelayed(new Runnable() { public void run() { mWindow.setVisibility(View.GONE); refresh(); // TODO: "pin area" panel, dragging things out ObjectAnimator mAnimHide, mAnimShow; protected void onAttachedToWindow() { } }, 250); public boolean holding() { return (mClipping != null); } private void stash(ClipData clipping) { mClipping = clipping; if (mClipping != null) { setVisibility(View.VISIBLE); Bitmap icon = mClipping.getIcon(); mDescription.setText(mClipping.getDescription().getLabel()); // mDescription.setText(mClipping.getDescription().getLabel()); if (icon != null) { mPreviewIcon.setImageBitmap(icon); mPreviewIcon.setVisibility(View.VISIBLE); mAltText.setVisibility(View.GONE); setImageBitmap(icon); } else { mPreviewIcon.setVisibility(View.GONE); mAltText.setVisibility(View.VISIBLE); if (mClipping.getItemCount() > 0) { // TODO: figure out how to visualize every kind of ClipData! mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext())); //mAltText.setText(mClipping.getItemAt(0).coerceToText(getContext())); } } } else { setVisibility(View.GONE); } } @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); if (action == MotionEvent.ACTION_DOWN) { final ClipData clip = mClipping; if (clip != null) { final Bitmap icon = clip.getIcon(); DragShadowBuilder shadow; if (icon != null) { shadow = new DragShadowBuilder(this) { public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { shadowSize.set(icon.getWidth(), icon.getHeight()); shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2); } public void onDrawShadow(Canvas canvas) { canvas.drawBitmap(icon, 0, 0, new Paint()); } }; } else { // uhhh, what now? shadow = new DragShadowBuilder(this); } startDrag(clip, shadow, null, 0); // TODO: only discard the clipping if it was accepted stash(null); return true; } } return false; } /* private boolean isInViewContentArea(View v, int x, int y) { final int l = v.getPaddingLeft(); final int r = v.getWidth() - v.getPaddingRight(); Loading Loading @@ -167,38 +231,12 @@ public class ShirtPocket extends ImageView { // TODO: only discard the clipping if it was accepted stash(null); hideWindowInJustASec(); // will refresh the icon return true; } } return false; } }; public boolean onDragEvent(DragEvent event) { if (DEBUG) Slog.d(TAG, "onDragEvent: " + event); switch (event.getAction()) { // We want to appear whenever a potential drag takes off from anywhere in the UI. case DragEvent.ACTION_DRAG_STARTED: // XXX: TODO break; case DragEvent.ACTION_DRAG_ENTERED: if (DEBUG) Slog.d(TAG, "entered!"); // XXX: TODO break; case DragEvent.ACTION_DRAG_EXITED: if (DEBUG) Slog.d(TAG, "exited!"); setVisibility(mClipping == null ? View.GONE : View.VISIBLE); break; case DragEvent.ACTION_DROP: if (DEBUG) Slog.d(TAG, "dropped!"); stash(event.getClipData()); break; case DragEvent.ACTION_DRAG_ENDED: break; } return true; // we want everything, thank you } */ }