summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/proguard.flags2
-rw-r--r--packages/SystemUI/res/layout/recents_task_view.xml23
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Constants.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsService.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java163
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java101
13 files changed, 464 insertions, 39 deletions
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 48d9722..da37803 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -6,7 +6,7 @@
public void setGlowAlpha(float);
public void setGlowScale(float);
}
--keep class com.android.systemui.recents.views.TaskIconView {
+-keep class com.android.systemui.recents.views.TaskInfoView {
public void setCircularClipRadius(float);
public float getCircularClipRadius();
}
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 8297878..7f64032 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -21,6 +21,21 @@
android:id="@+id/task_view_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <com.android.systemui.recents.views.TaskInfoView
+ android:id="@+id/task_view_info_pane"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ android:background="#e6444444">
+ <Button
+ android:id="@+id/task_view_app_info_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="20dp"
+ android:layout_marginEnd="20dp"
+ android:layout_gravity="top|center_horizontal"
+ android:text="@string/recents_app_info_button_label" />
+ </com.android.systemui.recents.views.TaskInfoView>
<com.android.systemui.recents.views.TaskBarView
android:id="@+id/task_view_bar"
android:layout_width="match_parent"
@@ -31,15 +46,15 @@
android:id="@+id/application_icon"
android:layout_width="@dimen/recents_task_view_application_icon_size"
android:layout_height="@dimen/recents_task_view_application_icon_size"
- android:layout_gravity="center_vertical|left"
+ android:layout_gravity="center_vertical|start"
android:padding="8dp" />
<TextView
android:id="@+id/activity_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|left"
- android:layout_marginLeft="@dimen/recents_task_view_application_icon_size"
- android:layout_marginRight="@dimen/recents_task_view_activity_icon_size"
+ android:layout_marginStart="@dimen/recents_task_view_application_icon_size"
+ android:layout_marginEnd="@dimen/recents_task_view_activity_icon_size"
android:textSize="24sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
@@ -52,7 +67,7 @@
android:id="@+id/activity_icon"
android:layout_width="@dimen/recents_task_view_activity_icon_size"
android:layout_height="@dimen/recents_task_view_activity_icon_size"
- android:layout_gravity="center_vertical|right"
+ android:layout_gravity="center_vertical|end"
android:padding="12dp"
android:visibility="invisible" />
</com.android.systemui.recents.views.TaskBarView>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index e305d94..478c541 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -114,6 +114,8 @@
<integer name="recents_filter_animate_new_views_min_duration">125</integer>
<!-- The min animation duration for animating views that are newly visible. -->
<integer name="recents_animate_task_bar_enter_duration">200</integer>
+ <!-- The animation duration for animating in the info pane. -->
+ <integer name="recents_animate_task_view_info_pane_duration">150</integer>
<!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
card. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5e7db8b..94d3541 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -239,6 +239,9 @@
<!-- The size of the activity icon in the recents task view. -->
<dimen name="recents_task_view_activity_icon_size">60dp</dimen>
+ <!-- The amount of space a user has to scroll to dismiss any info panes. -->
+ <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
+
<!-- Used to calculate the translation animation duration, the expected amount of movement
in dps over one second of time. -->
<dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d994a5b..73e5e19 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -509,6 +509,8 @@
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">RECENTS</string>
+ <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
+ <string name="recents_app_info_button_label">Application Info</string>
<!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
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