diff options
author | Winson Chung <winsonc@google.com> | 2014-04-11 16:49:09 -0700 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2014-04-14 12:38:47 -0700 |
commit | 9f9679d91ee5f067cd5dcbf4d780a1f5b522e4ba (patch) | |
tree | 5481d9ae0b0d424422a2a89f51f47d776e081666 /packages/SystemUI/src/com/android/systemui/recents | |
parent | 7bc016e88a854d8de870ddb6e235fab3c902c0c7 (diff) | |
download | frameworks_base-9f9679d91ee5f067cd5dcbf4d780a1f5b522e4ba.zip frameworks_base-9f9679d91ee5f067cd5dcbf4d780a1f5b522e4ba.tar.gz frameworks_base-9f9679d91ee5f067cd5dcbf4d780a1f5b522e4ba.tar.bz2 |
Adding experiment for app-info pane.
Change-Id: I647de1a71a2ac82da0a4f8a24125496dd5457441
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/recents')
8 files changed, 437 insertions, 34 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index cde17f5..64770a4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -28,8 +28,9 @@ public class Constants { public static class App { public static final boolean EnableTaskFiltering = true; public static final boolean EnableTaskStackClipping = false; - public static final boolean EnableToggleNewRecentsActivity = false; - // This disables the bitmap and icon caches to + public static final boolean EnableInfoPane = true; + + // This disables the bitmap and icon caches public static final boolean DisableBackgroundCache = false; // For debugging, this enables us to create mock recents tasks public static final boolean EnableSystemServicesProxy = false; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index f61c28c..f61c9f1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -50,11 +50,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView String action = intent.getAction(); Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed); - if (action.equals(RecentsService.ACTION_FINISH_RECENTS_ACTIVITY)) { - if (Constants.DebugFlags.App.EnableToggleNewRecentsActivity) { - finish(); - } - } else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) { + if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) { // Try and unfilter and filtered stacks if (!mRecentsView.unfilterFilteredStacks()) { // If there are no filtered stacks, dismiss recents and launch the first task @@ -190,7 +186,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Register the broadcast receiver to handle messages from our service IntentFilter filter = new IntentFilter(); filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY); - filter.addAction(RecentsService.ACTION_FINISH_RECENTS_ACTIVITY); registerReceiver(mServiceBroadcastReceiver, filter); // Register the broadcast receiver to handle messages when the screen is turned off @@ -224,11 +219,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView Console.AnsiRed); super.onStop(); - // Finish the current recents activity after we have launched a task - if (mTaskLaunched && Constants.DebugFlags.App.EnableToggleNewRecentsActivity) { - finish(); - } - mVisible = false; mTaskLaunched = false; } @@ -250,8 +240,18 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void onBackPressed() { - if (!mRecentsView.unfilterFilteredStacks()) { - super.onBackPressed(); + boolean interceptedByInfoPanelClose = false; + + // Try and return from any open info panes + if (Constants.DebugFlags.App.EnableInfoPane) { + interceptedByInfoPanelClose = mRecentsView.closeOpenInfoPanes(); + } + + // If we haven't been intercepted already, then unfilter any stacks + if (!interceptedByInfoPanelClose) { + if (!mRecentsView.unfilterFilteredStacks()) { + super.onBackPressed(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 8949663..9fdb5f9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -40,6 +40,8 @@ public class RecentsConfiguration { public int filteringCurrentViewsMinAnimDuration; public int filteringNewViewsMinAnimDuration; public int taskBarEnterAnimDuration; + public int taskStackScrollDismissInfoPaneDistance; + public int taskViewInfoPaneAnimDuration; public boolean launchedWithThumbnailAnimation; @@ -81,6 +83,10 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_filter_animate_new_views_min_duration); taskBarEnterAnimDuration = res.getInteger(R.integer.recents_animate_task_bar_enter_duration); + taskStackScrollDismissInfoPaneDistance = res.getDimensionPixelSize( + R.dimen.recents_task_stack_scroll_dismiss_info_pane_distance); + taskViewInfoPaneAnimDuration = + res.getInteger(R.integer.recents_animate_task_view_info_pane_duration); } /** Updates the system insets */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java index f78a999..06ca9e2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java @@ -112,7 +112,6 @@ class SystemUIMessageHandler extends Handler { /* Service */ public class RecentsService extends Service { - final static String ACTION_FINISH_RECENTS_ACTIVITY = "action_finish_recents_activity"; final static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity"; Messenger mSystemUIMessenger = new Messenger(new SystemUIMessageHandler(this)); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index ec28379..b054a22 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -17,13 +17,16 @@ package com.android.systemui.recents.views; import android.app.ActivityOptions; +import android.app.TaskStackBuilder; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; +import android.net.Uri; import android.os.UserHandle; +import android.provider.Settings; import android.view.View; import android.widget.FrameLayout; import com.android.systemui.recents.Console; @@ -179,6 +182,21 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV return true; } + /** Closes any open info panes */ + public boolean closeOpenInfoPanes() { + if (mBSP != null) { + // Get the first stack view + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + TaskStackView stackView = (TaskStackView) getChildAt(i); + if (stackView.closeOpenInfoPanes()) { + return true; + } + } + } + return false; + } + /** Unfilters any filtered stacks */ public boolean unfilterFilteredStacks() { if (mBSP != null) { @@ -206,6 +224,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV mCb.onTaskLaunching(); } + // Close any open info panes + closeOpenInfoPanes(); + final Runnable launchRunnable = new Runnable() { @Override public void run() { @@ -283,4 +304,15 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV tv.animateOnLeavingRecents(launchRunnable); } } + + @Override + public void onTaskAppInfoLaunched(Task t) { + // Create a new task stack with the application info details activity + Intent baseIntent = t.key.baseIntent; + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null)); + intent.setComponent(intent.resolveActivity(getContext().getPackageManager())); + TaskStackBuilder.create(getContext()) + .addNextIntentWithParentStack(intent).startActivities(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java new file mode 100644 index 0000000..233e38c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2014 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.android.systemui.recents.views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.widget.Button; +import android.widget.FrameLayout; +import com.android.systemui.R; +import com.android.systemui.recents.BakedBezierInterpolator; +import com.android.systemui.recents.Utilities; + + +/* The task info view */ +class TaskInfoView extends FrameLayout { + + Button mAppInfoButton; + + // Circular clip animation + boolean mCircularClipEnabled; + Path mClipPath = new Path(); + float mClipRadius; + float mMaxClipRadius; + Point mClipOrigin = new Point(); + ObjectAnimator mCircularClipAnimator; + + public TaskInfoView(Context context) { + this(context, null); + } + + public TaskInfoView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onFinishInflate() { + // Initialize the buttons on the info panel + mAppInfoButton = (Button) findViewById(R.id.task_view_app_info_button); + } + + /** Updates the positions of each of the items to fit in the rect specified */ + void updateContents(Rect visibleRect) { + // Offset the app info button + LayoutParams lp = (LayoutParams) mAppInfoButton.getLayoutParams(); + lp.topMargin = visibleRect.top + + (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2; + requestLayout(); + } + + /** Sets the circular clip radius on this panel */ + public void setCircularClipRadius(float r) { + mClipRadius = r; + invalidate(); + } + + /** Gets the circular clip radius on this panel */ + public float getCircularClipRadius() { + return mClipRadius; + } + + /** Animates the circular clip radius on the icon */ + void animateCircularClip(Point o, float fromRadius, float toRadius, + final Runnable postRunnable, boolean animateInContent) { + if (mCircularClipAnimator != null) { + mCircularClipAnimator.cancel(); + } + + // Calculate the max clip radius to each of the corners + int w = getMeasuredWidth() - o.x; + int h = getMeasuredHeight() - o.y; + // origin to tl, tr, br, bl + mMaxClipRadius = (int) Math.ceil(Math.sqrt(o.x * o.x + o.y * o.y)); + mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + o.y * o.y))); + mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + h * h))); + mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(o.x * o.x + h * h))); + + mClipOrigin.set(o.x, o.y); + mClipRadius = fromRadius; + int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius); + mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius); + mCircularClipAnimator.setDuration(duration); + mCircularClipAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); + mCircularClipAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCircularClipEnabled = false; + if (postRunnable != null) { + postRunnable.run(); + } + } + }); + mCircularClipAnimator.start(); + mCircularClipEnabled = true; + + if (animateInContent) { + animateAppInfoButtonIn(duration); + } + } + + /** Cancels the circular clip animation. */ + void cancelCircularClipAnimation() { + if (mCircularClipAnimator != null) { + mCircularClipAnimator.cancel(); + } + } + + void animateAppInfoButtonIn(int duration) { + mAppInfoButton.setScaleX(0.75f); + mAppInfoButton.setScaleY(0.75f); + mAppInfoButton.animate() + .scaleX(1f) + .scaleY(1f) + .setDuration(duration) + .setInterpolator(BakedBezierInterpolator.INSTANCE) + .withLayer() + .start(); + } + + @Override + public void draw(Canvas canvas) { + int saveCount = 0; + if (mCircularClipEnabled) { + saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); + mClipPath.reset(); + mClipPath.addCircle(mClipOrigin.x, mClipOrigin.y, mClipRadius * mMaxClipRadius, + Path.Direction.CW); + canvas.clipPath(mClipPath); + } + super.draw(canvas); + if (mCircularClipEnabled) { + canvas.restoreToCount(saveCount); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 88fb972..033bd67 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -52,11 +52,12 @@ import java.util.HashMap; /* The visual representation of a task stack view */ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks, TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>, - View.OnClickListener { + View.OnClickListener, View.OnLongClickListener { /** The TaskView callbacks */ interface TaskStackViewCallbacks { public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t); + public void onTaskAppInfoLaunched(Task t); } TaskStack mStack; @@ -75,6 +76,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int mMinScroll; int mMaxScroll; int mStashedScroll; + int mLastInfoPaneStackScroll; OverScroller mScroller; ObjectAnimator mScrollAnimator; @@ -281,6 +283,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void setStackScroll(int value) { mStackScroll = value; requestSynchronizeStackViewsWithModel(); + + // Close any open info panes if the user has scrolled away from them + boolean isAnimatingScroll = (mScrollAnimator != null && mScrollAnimator.isRunning()); + if (mLastInfoPaneStackScroll > -1 && !isAnimatingScroll) { + RecentsConfiguration config = RecentsConfiguration.getInstance(); + if (Math.abs(mStackScroll - mLastInfoPaneStackScroll) > + config.taskStackScrollDismissInfoPaneDistance) { + // Close any open info panes + closeOpenInfoPanes(); + } + } } /** Sets the current stack scroll without synchronizing the stack view with the model */ public void setStackScrollRaw(int value) { @@ -300,19 +313,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Enable hw layers on the stack addHwLayersRefCount("animateBoundScroll"); - // Abort any current animations - abortScroller(); - abortBoundScrollAnimation(); - // Start a new scroll animation - animateScroll(curScroll, newScroll); - mScrollAnimator.start(); + animateScroll(curScroll, newScroll, new Runnable() { + @Override + public void run() { + // Disable hw layers on the stack + decHwLayersRefCount("animateBoundScroll"); + } + }); } return mScrollAnimator; } /** Animates the stack scroll */ - void animateScroll(int curScroll, int newScroll) { + void animateScroll(int curScroll, int newScroll, final Runnable postRunnable) { + // Abort any current animations + abortScroller(); + abortBoundScrollAnimation(); + mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll); mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll - curScroll, 250)); @@ -326,20 +344,23 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mScrollAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - // Disable hw layers on the stack - decHwLayersRefCount("animateBoundScroll"); + if (postRunnable != null) { + postRunnable.run(); + } + mScrollAnimator.removeAllListeners(); } }); + mScrollAnimator.start(); } /** Aborts any current stack scrolls */ void abortBoundScrollAnimation() { if (mScrollAnimator != null) { mScrollAnimator.cancel(); - mScrollAnimator.removeAllListeners(); } } + /** Aborts the scroller and any current fling */ void abortScroller() { if (!mScroller.isFinished()) { // Abort the scroller @@ -407,6 +428,21 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + /** Closes any open info panes. */ + boolean closeOpenInfoPanes() { + if (!Constants.DebugFlags.App.EnableInfoPane) return false; + + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + TaskView tv = (TaskView) getChildAt(i); + if (tv.isInfoPaneVisible()) { + tv.hideInfoPane(); + return true; + } + } + return false; + } + /** Enables the hw layers and increments the hw layer requirement ref count */ void addHwLayersRefCount(String reason) { Console.log(Constants.DebugFlags.UI.HwLayers, @@ -644,7 +680,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement)); } - /** * Creates the animations for all the children views that need to be removed or to move views * to their un/filtered position when we are un/filtering a stack, and returns the duration @@ -789,6 +824,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks, Task filteredTask) { + // Close any open info panes + closeOpenInfoPanes(); + // Stash the scroll and filtered task for us to restore to when we unfilter mStashedScroll = getStackScroll(); @@ -813,6 +851,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) { + // Close any open info panes + closeOpenInfoPanes(); + // Calculate the current task transforms final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curTasks, getStackScroll(), null, true); @@ -892,6 +933,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Set the callbacks and listeners for this new view tv.setOnClickListener(this); + if (Constants.DebugFlags.App.EnableInfoPane) { + tv.setOnLongClickListener(this); + } tv.setCallbacks(this); } else { attachViewToParent(tv, insertIndex, tv.getLayoutParams()); @@ -926,6 +970,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + @Override + public void onTaskInfoPanelShown(TaskView tv) { + // Do nothing + } + + @Override + public void onTaskInfoPanelHidden(TaskView tv) { + // Unset the saved scroll + mLastInfoPaneStackScroll = -1; + } + + @Override + public void onTaskAppInfoClicked(TaskView tv) { + if (mCb != null) { + mCb.onTaskAppInfoLaunched(tv.getTask()); + } + } + /**** View.OnClickListener Implementation ****/ @Override @@ -935,10 +997,51 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]", task + " cb: " + mCb); + // Close any open info panes if the user taps on another task + if (closeOpenInfoPanes()) { + return; + } + if (mCb != null) { mCb.onTaskLaunched(this, tv, mStack, task); } } + + @Override + public boolean onLongClick(View v) { + if (!Constants.DebugFlags.App.EnableInfoPane) return false; + + TaskView tv = (TaskView) v; + + // Close any other task info panels if we launch another info pane + closeOpenInfoPanes(); + + // Scroll the task view so that it is maximally visible + float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height(); + int taskIndex = mStack.indexOfTask(tv.getTask()); + int curScroll = getStackScroll(); + int newScroll = (int) Math.max(mMinScroll, Math.min(mMaxScroll, taskIndex * overlapHeight)); + TaskViewTransform transform = getStackTransform(taskIndex, curScroll); + Rect nonOverlapRect = new Rect(transform.rect); + if (taskIndex < (mStack.getTaskCount() - 1)) { + nonOverlapRect.bottom = nonOverlapRect.top + (int) overlapHeight; + } + + // XXX: Use HW Layers + if (transform.t < 0f) { + animateScroll(curScroll, newScroll, null); + } else if (nonOverlapRect.bottom > mStackRectSansPeek.bottom) { + // Check if we are out of bounds, if so, just scroll it in such that the bottom of the + // task view is visible + newScroll = curScroll - (mStackRectSansPeek.bottom - nonOverlapRect.bottom); + animateScroll(curScroll, newScroll, null); + } + mLastInfoPaneStackScroll = newScroll; + + // Show the info pane for this task view + tv.showInfoPane(new Rect(0, 0, 0, (int) overlapHeight)); + return true; + } } /* Handles touch events */ @@ -1153,9 +1256,10 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { int activePointerIndex = ev.findPointerIndex(mActivePointerId); int x = (int) ev.getX(activePointerIndex); int y = (int) ev.getY(activePointerIndex); + int yTotal = Math.abs(y - mInitialMotionY); int deltaY = mLastMotionY - y; if (!mIsScrolling) { - if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) { + if (yTotal > mScrollTouchSlop) { mIsScrolling = true; // Initialize the velocity tracker initOrResetVelocityTracker(); @@ -1277,6 +1381,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } + // If the info panel is currently showing on this view, then we need to dismiss it + if (Constants.DebugFlags.App.EnableInfoPane) { + TaskView tv = (TaskView) v; + if (tv.isInfoPaneVisible()) { + tv.hideInfoPane(); + } + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index b410012..81805d5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -17,8 +17,10 @@ package com.android.systemui.recents.views; import android.content.Context; +import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import com.android.systemui.R; @@ -29,18 +31,26 @@ import com.android.systemui.recents.model.Task; /* A task view */ -public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks { +public class TaskView extends FrameLayout implements View.OnClickListener, + Task.TaskCallbacks { /** The TaskView callbacks */ interface TaskViewCallbacks { public void onTaskIconClicked(TaskView tv); + public void onTaskInfoPanelShown(TaskView tv); + public void onTaskInfoPanelHidden(TaskView tv); + public void onTaskAppInfoClicked(TaskView tv); + // public void onTaskViewReboundToTask(TaskView tv, Task t); } Task mTask; boolean mTaskDataLoaded; + boolean mTaskInfoPaneVisible; + Point mLastTouchDown = new Point(); TaskThumbnailView mThumbnailView; TaskBarView mBarView; + TaskInfoView mInfoView; TaskViewCallbacks mCb; @@ -65,12 +75,24 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. // Bind the views mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail); mBarView = (TaskBarView) findViewById(R.id.task_view_bar); - mBarView.mApplicationIcon.setOnClickListener(this); + mInfoView = (TaskInfoView) findViewById(R.id.task_view_info_pane); + if (mTaskDataLoaded) { onTaskDataLoaded(false); } } + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + mLastTouchDown.set((int) ev.getX(), (int) ev.getY()); + break; + } + return super.onInterceptTouchEvent(ev); + } + /** Set callback */ void setCallbacks(TaskViewCallbacks cb) { mCb = cb; @@ -189,6 +211,63 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. return outRect; } + /** Returns whether this task has an info pane visible */ + boolean isInfoPaneVisible() { + return mTaskInfoPaneVisible; + } + + /** Shows the info pane if it is not visible. */ + void showInfoPane(Rect taskVisibleRect) { + if (mTaskInfoPaneVisible) return; + + // Remove the bar view from the visible rect and update the info pane contents + taskVisibleRect.top += mBarView.getMeasuredHeight(); + mInfoView.updateContents(taskVisibleRect); + + // Show the info pane and animate it into view + mInfoView.setVisibility(View.VISIBLE); + mInfoView.animateCircularClip(mLastTouchDown, 0f, 1f, null, true); + mInfoView.setOnClickListener(this); + mTaskInfoPaneVisible = true; + + // Notify any callbacks + if (mCb != null) { + mCb.onTaskInfoPanelShown(this); + } + } + + /** Hides the info pane if it is visible. */ + void hideInfoPane() { + if (!mTaskInfoPaneVisible) return; + RecentsConfiguration config = RecentsConfiguration.getInstance(); + + // Cancel any circular clip animation + mInfoView.cancelCircularClipAnimation(); + + // Animate the info pane out + mInfoView.animate() + .alpha(0f) + .setDuration(config.taskViewInfoPaneAnimDuration) + .setInterpolator(BakedBezierInterpolator.INSTANCE) + .withLayer() + .withEndAction(new Runnable() { + @Override + public void run() { + mInfoView.setVisibility(View.INVISIBLE); + mInfoView.setOnClickListener(null); + + mInfoView.setAlpha(1f); + } + }) + .start(); + mTaskInfoPaneVisible = false; + + // Notify any callbacks + if (mCb != null) { + mCb.onTaskInfoPanelHidden(this); + } + } + /** Enable the hw layers on this task view */ void enableHwLayers() { mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null); @@ -209,27 +288,39 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. @Override public void onTaskDataLoaded(boolean reloadingTaskData) { - if (mThumbnailView != null && mBarView != null) { + if (mThumbnailView != null && mBarView != null && mInfoView != null) { // Bind each of the views to the new task data mThumbnailView.rebindToTask(mTask, reloadingTaskData); mBarView.rebindToTask(mTask, reloadingTaskData); + // Rebind any listeners + mBarView.mApplicationIcon.setOnClickListener(this); + mInfoView.mAppInfoButton.setOnClickListener(this); } mTaskDataLoaded = true; } @Override public void onTaskDataUnloaded() { - if (mThumbnailView != null && mBarView != null) { + if (mThumbnailView != null && mBarView != null && mInfoView != null) { // Unbind each of the views from the task data and remove the task callback mTask.setCallbacks(null); mThumbnailView.unbindFromTask(); mBarView.unbindFromTask(); + // Unbind any listeners + mBarView.mApplicationIcon.setOnClickListener(null); + mInfoView.mAppInfoButton.setOnClickListener(null); } mTaskDataLoaded = false; } @Override public void onClick(View v) { - mCb.onTaskIconClicked(this); + if (v == mInfoView) { + // Do nothing + } else if (v == mBarView.mApplicationIcon) { + mCb.onTaskIconClicked(this); + } else if (v == mInfoView.mAppInfoButton) { + mCb.onTaskAppInfoClicked(this); + } } }
\ No newline at end of file |