OSDN Git Service

Adding history view.
authorWinson <winsonc@google.com>
Sat, 21 Nov 2015 00:00:45 +0000 (16:00 -0800)
committerWinson <winsonc@google.com>
Wed, 25 Nov 2015 19:42:19 +0000 (11:42 -0800)
- Initial changes to show a history view within Overview (behind tuner
  flag)
- Restoring the task view dim in the stack

Change-Id: I0503d11768736c86f3145942404391dfacd0ddd6

23 files changed:
packages/SystemUI/Android.mk
packages/SystemUI/res/layout/recents.xml
packages/SystemUI/res/layout/recents_history.xml [new file with mode: 0644]
packages/SystemUI/res/layout/recents_history_button.xml [new file with mode: 0644]
packages/SystemUI/res/layout/recents_history_date.xml [new file with mode: 0644]
packages/SystemUI/res/layout/recents_history_task.xml [new file with mode: 0644]
packages/SystemUI/res/values/config.xml
packages/SystemUI/res/values/strings.xml
packages/SystemUI/res/xml/tuner_prefs.xml
packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
packages/SystemUI/tests/Android.mk

index 0cc2a67..ece34fb 100644 (file)
@@ -6,7 +6,9 @@ LOCAL_MODULE_TAGS := optional
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) $(call all-Iaidl-files-under, src) \
     src/com/android/systemui/EventLogTags.logtags
 
-LOCAL_STATIC_JAVA_LIBRARIES := Keyguard
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    Keyguard \
+    android-support-v7-recyclerview
 LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUI
index 064d225..2c010dd 100644 (file)
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
 
+    <!-- History View -->
+    <ViewStub android:id="@+id/history_view_stub"
+           android:layout="@layout/recents_history"
+           android:layout_width="match_parent"
+           android:layout_height="match_parent" />
+
     <!-- Nav Bar Scrim View -->
     <ImageView
         android:id="@+id/nav_bar_scrim"
diff --git a/packages/SystemUI/res/layout/recents_history.xml b/packages/SystemUI/res/layout/recents_history.xml
new file mode 100644 (file)
index 0000000..de70d30
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<com.android.systemui.recents.history.RecentsHistoryView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#99000000"
+    android:orientation="vertical">
+    <TextView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="14dp"
+        android:gravity="start"
+        android:text="@string/recents_history_label"
+        android:textSize="24sp"
+        android:textColor="#FFFFFF"
+        android:fontFamily="sans-serif-medium" />
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</com.android.systemui.recents.history.RecentsHistoryView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_button.xml b/packages/SystemUI/res/layout/recents_history_button.xml
new file mode 100644 (file)
index 0000000..38457c7
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/recents_history_button_height"
+    android:gravity="start|center_vertical"
+    android:text="@string/recents_show_history_button_label"
+    android:textSize="14sp"
+    android:textColor="#FFFFFF"
+    android:textAllCaps="true"
+    android:fontFamily="sans-serif-medium"
+    android:visibility="invisible" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_date.xml b/packages/SystemUI/res/layout/recents_history_date.xml
new file mode 100644 (file)
index 0000000..6d6a9ee
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:theme="@android:style/Theme.Material"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="12dp"
+    android:gravity="start"
+    android:textSize="14sp"
+    android:textColor="#009688"
+    android:textAllCaps="true"
+    android:fontFamily="sans-serif-medium"
+    android:background="?android:selectableItemBackground"
+    android:alpha="1" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_task.xml b/packages/SystemUI/res/layout/recents_history_task.xml
new file mode 100644 (file)
index 0000000..b9de156
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:theme="@android:style/Theme.Material"
+    android:layout_width="match_parent"
+    android:layout_height="48dp"
+    android:paddingLeft="32dp"
+    android:gravity="start|center_vertical"
+    android:textSize="14sp"
+    android:textColor="#FFFFFF"
+    android:fontFamily="sans-serif-medium"
+    android:background="?android:selectableItemBackground"
+    android:alpha="1" />
\ No newline at end of file
index d8193ab..902db26 100644 (file)
     <!-- The animation duration for scrolling the stack to a particular item. -->
     <integer name="recents_animate_task_stack_scroll_duration">225</integer>
 
+    <!-- The animation duration for entering and exiting the history. -->
+    <integer name="recents_history_transition_duration">250</integer>
+
     <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
     <integer name="recents_max_task_stack_view_dim">96</integer>
 
index e0c0f6a..04233ba 100644 (file)
     <string name="recents_search_bar_label">search</string>
     <!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
     <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+    <!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
+    <string name="recents_show_history_button_label">More</string>
+    <!-- Recents: The history of recents. [CHAR LIMIT=NONE] -->
+    <string name="recents_history_label">History</string>
 
     <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
     <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
     <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
     <string name="qs_paging" translatable="false">Use the new Quick Settings</string>
 
-    <!-- Toggles paging recents via the recents button -->
+    <!-- Toggles paging recents via the recents button. DO NOT TRANSLATE -->
     <string name="overview_page_on_toggle">Enable paging</string>
-    <!-- Description for the toggle for fast-toggling recents via the recents button -->
+    <!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
     <string name="overview_page_on_toggle_desc">Enable paging via the Overview button</string>
 
-    <!-- Toggles fast-toggling recents via the recents button -->
+    <!-- Toggles fast-toggling recents via the recents button. DO NOT TRANSLATE -->
     <string name="overview_fast_toggle_via_button">Enable fast toggle</string>
-    <!-- Description for the toggle for fast-toggling recents via the recents button -->
+    <!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
     <string name="overview_fast_toggle_via_button_desc">Enable launch timeout while paging</string>
 
-    <!-- Toggles fullscreen screenshots -->
+    <!-- Toggles fullscreen screenshots. DO NOT TRANSLATE -->
     <string name="overview_fullscreen_thumbnails">Enable fullscreen screenshots</string>
-    <!-- Description for the toggle for fullscreen screenshots -->
+    <!-- Description for the toggle for fullscreen screenshots. DO NOT TRANSLATE -->
     <string name="overview_fullscreen_thumbnails_desc">Enable fullscreen screenshots in Overview</string>
 
+    <!-- Toggle to show the history view in Overview. DO NOT TRANSLATE -->
+    <string name="overview_show_history">Show History</string>
+    <!-- Description for the toggle to show the history view in Overview. DO NOT TRANSLATE -->
+    <string name="overview_show_history_desc">Enables the history view to see more recent tasks</string>
+
     <!-- Category in the System UI Tuner settings, where new/experimental
          settings are -->
     <string name="experimental">Experimental</string>
index 4d07d5f..f398af3 100644 (file)
             android:title="@string/overview_fullscreen_thumbnails"
             android:summary="@string/overview_fullscreen_thumbnails_desc" />
 
+        <com.android.systemui.tuner.TunerSwitch
+            android:key="overview_show_history"
+            android:title="@string/overview_show_history"
+            android:summary="@string/overview_show_history_desc" />
+
     </PreferenceScreen>
 
     <SwitchPreference
index 16b1592..66a5106 100644 (file)
@@ -27,6 +27,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -46,10 +47,12 @@ import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnim
 import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.HideHistoryEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
+import com.android.systemui.recents.events.activity.ShowHistoryEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -65,6 +68,7 @@ import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
+import com.android.systemui.recents.history.RecentsHistoryView;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -99,6 +103,8 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     private SystemBarScrimViews mScrimViews;
     private ViewStub mEmptyViewStub;
     private View mEmptyView;
+    private ViewStub mHistoryViewStub;
+    private RecentsHistoryView mHistoryView;
 
     // Resize task debug
     private RecentsResizeTaskDialog mResizeTaskDebugDialog;
@@ -260,6 +266,18 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     }
 
     /**
+     * Dismisses the history view back into the stack view.
+     */
+    boolean dismissHistory() {
+        // Try and hide the history view first
+        if (mHistoryView != null && mHistoryView.isVisible()) {
+            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Dismisses recents if we are already visible and the intent is to toggle the recents view.
      */
     boolean dismissRecentsToFocusedTask() {
@@ -349,6 +367,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
         mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
+        mHistoryViewStub = (ViewStub) findViewById(R.id.history_view_stub);
         mScrimViews = new SystemBarScrimViews(this);
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -432,6 +451,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
 
         // Reset some states
         mIgnoreAltTabRelease = false;
+        if (mHistoryView != null) {
+            EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
+        }
 
         // Notify that recents is now hidden
         SystemServicesProxy ssp = Recents.getSystemServices();
@@ -550,8 +572,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
 
     @Override
     public void onBackPressed() {
-        // Dismiss Recents to the focused Task or Home
-        dismissRecentsToFocusedTaskOrHome();
+        if (!dismissHistory()) {
+            dismissRecentsToFocusedTaskOrHome();
+        }
     }
 
     /**** RecentsResizeTaskDialog ****/
@@ -566,7 +589,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     /**** EventBus events ****/
 
     public final void onBusEvent(ToggleRecentsEvent event) {
-        dismissRecentsToFocusedTaskOrHome();
+        if (!dismissHistory()) {
+            dismissRecentsToFocusedTaskOrHome();
+        }
     }
 
     public final void onBusEvent(IterateRecentsEvent event) {
@@ -596,7 +621,21 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
             }
         } else if (event.triggeredFromHomeKey) {
             // Otherwise, dismiss Recents to Home
-            dismissRecentsToHome(true /* animated */);
+            if (mHistoryView != null && mHistoryView.isVisible()) {
+                ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
+                t.increment();
+                t.addLastDecrementRunnable(new Runnable() {
+                    @Override
+                    public void run() {
+                        dismissRecentsToHome(true /* animated */);
+                    }
+                });
+                EventBus.getDefault().send(new HideHistoryEvent(true, t));
+                t.decrement();
+
+            } else {
+                dismissRecentsToHome(true /* animated */);
+            }
         } else {
             // Do nothing
         }
@@ -726,6 +765,23 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
         mIgnoreAltTabRelease = true;
     }
 
+    public final void onBusEvent(ShowHistoryEvent event) {
+        if (mHistoryView == null) {
+            mHistoryView = (RecentsHistoryView) mHistoryViewStub.inflate();
+            // Since this history view is inflated by a view stub after the insets have already
+            // been applied, we have to set them ourselves initial from the insets that were last
+            // provided.
+            mHistoryView.setSystemInsets(mRecentsView.getSystemInsets());
+        }
+        mHistoryView.show(mRecentsView.getTaskStack());
+    }
+
+    public final void onBusEvent(HideHistoryEvent event) {
+        if (mHistoryView != null) {
+            mHistoryView.hide(event.animate, event.postAnimationTrigger);
+        }
+    }
+
     private void refreshSearchWidgetView() {
         if (mSearchWidgetInfo != null) {
             SystemServicesProxy ssp = Recents.getSystemServices();
index 67d7115..e8b8816 100644 (file)
@@ -29,6 +29,7 @@ public class RecentsDebugFlags implements TunerService.Tunable {
     private static final String KEY_FAST_TOGGLE = "overview_fast_toggle";
     private static final String KEY_PAGE_ON_TOGGLE = "overview_page_on_toggle";
     private static final String KEY_FULLSCREEN_THUMBNAILS = "overview_fullscreen_thumbnails";
+    private static final String KEY_SHOW_HISTORY = "overview_show_history";
 
     public static class Static {
         // Enables debug drawing for the transition thumbnail
@@ -52,6 +53,7 @@ public class RecentsDebugFlags implements TunerService.Tunable {
     private boolean mFastToggleRecents;
     private boolean mPageOnToggle;
     private boolean mUseFullscreenThumbnails;
+    private boolean mShowHistory;
 
     /**
      * We read the prefs once when we start the activity, then update them as the tuner changes
@@ -61,7 +63,7 @@ public class RecentsDebugFlags implements TunerService.Tunable {
         // Register all our flags, this will also call onTuningChanged() for each key, which will
         // initialize the current state of each flag
         TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE, KEY_PAGE_ON_TOGGLE,
-                KEY_FULLSCREEN_THUMBNAILS);
+                KEY_FULLSCREEN_THUMBNAILS, KEY_SHOW_HISTORY);
     }
 
     /**
@@ -85,6 +87,13 @@ public class RecentsDebugFlags implements TunerService.Tunable {
         return mUseFullscreenThumbnails;
     }
 
+    /**
+     * @return whether we should show the history
+     */
+    public boolean isHistoryEnabled() {
+        return mShowHistory;
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         switch (key) {
@@ -100,6 +109,10 @@ public class RecentsDebugFlags implements TunerService.Tunable {
                 mUseFullscreenThumbnails = (newValue != null) &&
                         (Integer.parseInt(newValue) != 0);
                 break;
+            case KEY_SHOW_HISTORY:
+                mShowHistory = (newValue != null) &&
+                        (Integer.parseInt(newValue) != 0);
+                break;
         }
         EventBus.getDefault().send(new DebugFlagsChangedEvent());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java
new file mode 100644 (file)
index 0000000..6c767e4
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the history view button should be hidden.
+ */
+public class HideHistoryButtonEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
new file mode 100644 (file)
index 0000000..34c35a7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+
+/**
+ * This is sent when the history view will be closed.
+ */
+public class HideHistoryEvent extends EventBus.Event {
+
+    public final boolean animate;
+    public final ReferenceCountedTrigger postAnimationTrigger;
+
+    public HideHistoryEvent(boolean animate) {
+        this(animate, null);
+    }
+
+    public HideHistoryEvent(boolean animate, ReferenceCountedTrigger postAnimationTrigger) {
+        this.animate = animate;
+        this.postAnimationTrigger = postAnimationTrigger;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
new file mode 100644 (file)
index 0000000..7042537
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the history view button should be shown.
+ */
+public class ShowHistoryButtonEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
new file mode 100644 (file)
index 0000000..870119d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the history view button is clicked.
+ */
+public class ShowHistoryEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
new file mode 100644 (file)
index 0000000..273f7bf
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 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.history;
+
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.v7.widget.RecyclerView;
+import android.text.format.DateFormat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+
+/**
+ * An adapter for the list of recent tasks in the history view.
+ */
+public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAdapter.ViewHolder> {
+
+    private static final String TAG = "RecentsHistoryView";
+    private static final boolean DEBUG = false;
+
+    static final int DATE_ROW_VIEW_TYPE = 0;
+    static final int TASK_ROW_VIEW_TYPE = 1;
+
+    /**
+     * View holder implementation.
+     */
+    public static class ViewHolder extends RecyclerView.ViewHolder {
+        public View mContent;
+
+        public ViewHolder(View v) {
+            super(v);
+            mContent = v;
+        }
+    }
+
+    /**
+     * A single row of content.
+     */
+    private interface Row {
+        int getViewType();
+    }
+
+    /**
+     * A date row.
+     */
+    private static class DateRow implements Row {
+
+        public final String date;
+
+        public DateRow(String date) {
+            this.date = date;
+        }
+
+        @Override
+        public int getViewType() {
+            return RecentsHistoryAdapter.DATE_ROW_VIEW_TYPE;
+        }
+    }
+
+    /**
+     * A task row.
+     */
+    private static class TaskRow implements Row, View.OnClickListener {
+
+        public final String description;
+        private final int mTaskId;
+
+        public TaskRow(Task task) {
+            mTaskId = task.key.id;
+            description = task.activityLabel;
+        }
+
+        @Override
+        public void onClick(View v) {
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ssp.startActivityFromRecents(v.getContext(), mTaskId, description,
+                    ActivityOptions.makeBasic());
+        }
+
+        @Override
+        public int getViewType() {
+            return RecentsHistoryAdapter.TASK_ROW_VIEW_TYPE;
+        }
+    }
+
+    private LayoutInflater mLayoutInflater;
+    private final List<Row> mRows = new ArrayList<>();
+
+    public RecentsHistoryAdapter(Context context, TaskStack stack) {
+        mLayoutInflater = LayoutInflater.from(context);
+        updateTasks(context, stack.getTasks());
+    }
+
+    /**
+     * Updates this adapter with the given tasks.
+     */
+    public void updateTasks(Context context, List<Task> tasks) {
+        final Locale l = context.getResources().getConfiguration().locale;
+        final String dateFormatStr = DateFormat.getBestDateTimePattern(l, "EEEEMMMMd");
+        final List<Task> tasksMostRecent = new ArrayList<>(tasks);
+        Collections.reverse(tasksMostRecent);
+        int prevDayKey = -1;
+        mRows.clear();
+        for (Task task : tasksMostRecent) {
+            if (SystemServicesProxy.isFreeformStack(task.key.stackId)) {
+                continue;
+            }
+
+            Calendar cal = Calendar.getInstance(l);
+            cal.setTimeInMillis(task.key.lastActiveTime);
+            int dayKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
+            if (dayKey != prevDayKey) {
+                prevDayKey = dayKey;
+                mRows.add(new DateRow(DateFormat.format(dateFormatStr, cal).toString()));
+            }
+            mRows.add(new TaskRow(task));
+        }
+    }
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        switch (viewType) {
+            case DATE_ROW_VIEW_TYPE:
+                return new ViewHolder(mLayoutInflater.inflate(R.layout.recents_history_date, parent,
+                        false));
+            case TASK_ROW_VIEW_TYPE:
+                return new ViewHolder(mLayoutInflater.inflate(R.layout.recents_history_task, parent,
+                        false));
+            default:
+                return new ViewHolder(null);
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        Row row = mRows.get(position);
+        int viewType = mRows.get(position).getViewType();
+        switch (viewType) {
+            case DATE_ROW_VIEW_TYPE: {
+                TextView tv = (TextView) holder.mContent;
+                tv.setText(((DateRow) row).date);
+                break;
+            }
+            case TASK_ROW_VIEW_TYPE: {
+                TextView tv = (TextView) holder.mContent;
+                TaskRow taskRow = (TaskRow) row;
+                tv.setText(taskRow.description);
+                tv.setOnClickListener(taskRow);
+                break;
+            }
+        }
+    }
+
+    @Override
+    public int getItemCount() {
+        return mRows.size();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mRows.get(position).getViewType();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
new file mode 100644 (file)
index 0000000..1ad79ae
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2015 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.history;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.recents.model.TaskStack;
+
+/**
+ * A list of the recent tasks that are not in the stack.
+ */
+public class RecentsHistoryView extends LinearLayout {
+
+    private static final String TAG = "RecentsHistoryView";
+    private static final boolean DEBUG = false;
+
+    private RecyclerView mRecyclerView;
+    private boolean mIsVisible;
+
+    private Interpolator mFastOutSlowInInterpolator;
+    private Interpolator mFastOutLinearInInterpolator;
+    private int mHistoryTransitionDuration;
+
+    public RecentsHistoryView(Context context) {
+        super(context);
+    }
+
+    public RecentsHistoryView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public RecentsHistoryView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public RecentsHistoryView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        Resources res = context.getResources();
+        mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
+    }
+
+    /**
+     * Updates this history view with the recent tasks, and then shows it.
+     */
+    public void show(TaskStack stack) {
+        setVisibility(View.VISIBLE);
+        setAlpha(0f);
+        animate()
+                .alpha(1f)
+                .setDuration(mHistoryTransitionDuration)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .withLayer()
+                .start();
+
+        mRecyclerView.setAdapter(new RecentsHistoryAdapter(getContext(), stack));
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        mIsVisible = true;
+    }
+
+    /**
+     * Hides this history view.
+     */
+    public void hide(boolean animate, final ReferenceCountedTrigger postAnimationTrigger) {
+        if (animate) {
+            animate()
+                    .alpha(0f)
+                    .setDuration(mHistoryTransitionDuration)
+                    .setInterpolator(mFastOutLinearInInterpolator)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            setVisibility(View.INVISIBLE);
+                            if (postAnimationTrigger != null) {
+                                postAnimationTrigger.decrement();
+                            }
+                        }
+                    })
+                    .withLayer()
+                    .start();
+            if (postAnimationTrigger != null) {
+                postAnimationTrigger.increment();
+            }
+        } else {
+            setAlpha(0f);
+            setVisibility(View.INVISIBLE);
+        }
+        mIsVisible = false;
+    }
+
+    /**
+     * Updates the system insets of this history view to the provided values.
+     */
+    public void setSystemInsets(Rect systemInsets) {
+        setPadding(systemInsets.left, systemInsets.top, systemInsets.right, systemInsets.bottom);
+    }
+
+    /**
+     * Returns whether this view is visible.
+     */
+    public boolean isVisible() {
+        return mIsVisible;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mRecyclerView = (RecyclerView) findViewById(R.id.list);
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        setSystemInsets(insets.getSystemWindowInsets());
+        return insets;
+    }
+}
index 90456c0..d700786 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.views;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -25,20 +26,26 @@ import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.View;
 import android.view.WindowInsets;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
-import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsAppWidgetHostView;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
+import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
+import com.android.systemui.recents.events.activity.ShowHistoryEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
@@ -63,11 +70,12 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
     private static final String TAG = "RecentsView";
     private static final boolean DEBUG = false;
 
-    LayoutInflater mInflater;
     Handler mHandler;
 
+    TaskStack mStack;
     TaskStackView mTaskStackView;
     RecentsAppWidgetHostView mSearchBar;
+    View mHistoryButton;
     boolean mAwaitingFirstLayout = true;
     boolean mLastTaskLaunchedWasFreeform;
 
@@ -81,7 +89,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
             TaskStack.DockState.BOTTOM,
     };
 
-    Interpolator mFastOutSlowInInterpolator;
+    private Interpolator mFastOutSlowInInterpolator;
+    private Interpolator mFastOutLinearInInterpolator;
+    private int mHistoryTransitionDuration;
 
     Rect mSystemInsets = new Rect();
 
@@ -99,18 +109,31 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
 
     public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        Resources res = context.getResources();
         setWillNotDraw(false);
-        mInflater = LayoutInflater.from(context);
         mHandler = new Handler();
         mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
+        mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
         mTouchHandler = new RecentsViewTouchHandler(this);
+
+        LayoutInflater inflater = LayoutInflater.from(context);
+        mHistoryButton = inflater.inflate(R.layout.recents_history_button, this, false);
+        mHistoryButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                EventBus.getDefault().send(new ShowHistoryEvent());
+            }
+        });
     }
 
     /** Set/get the bsp root node */
     public void setTaskStack(TaskStack stack) {
         RecentsConfiguration config = Recents.getConfiguration();
+        mStack = stack;
         if (config.getLaunchState().launchedReuseTaskStackViews) {
             if (mTaskStackView != null) {
                 // If onRecentsHidden is not triggered, we need to the stack view again here
@@ -129,6 +152,11 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
             mTaskStackView.setCallbacks(this);
             addView(mTaskStackView);
         }
+        if (indexOfChild(mHistoryButton) == -1) {
+            addView(mHistoryButton);
+        } else {
+            mHistoryButton.bringToFront();
+        }
 
         // Trigger a new layout
         requestLayout();
@@ -141,6 +169,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
         return mLastTaskLaunchedWasFreeform;
     }
 
+    /**
+     * Returns the currently set task stack.
+     */
+    public TaskStack getTaskStack() {
+        return mStack;
+    }
+
     /** Gets the next task in the stack - or if the last - the top task */
     public Task getNextTaskOrTopTask(Task taskToSearch) {
         Task returnTask = null;
@@ -219,10 +254,15 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
         }
         ctx.postAnimationTrigger.decrement();
 
+        // Hide the history button
+        int taskViewExitToHomeDuration = getResources().getInteger(
+                R.integer.recents_task_exit_to_home_duration);
+        hideHistoryButton(taskViewExitToHomeDuration);
+
         // If we are going home, cancel the previous task's window transition
         EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
 
-        // Notify of the exit animation
+        // Notify sof the exit animation
         EventBus.getDefault().send(new DismissRecentsToHomeAnimationStarted());
     }
 
@@ -253,6 +293,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
         }
     }
 
+    /**
+     * Returns the last known system insets.
+     */
+    public Rect getSystemInsets() {
+        return mSystemInsets;
+    }
+
     @Override
     protected void onAttachedToWindow() {
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
@@ -301,6 +348,10 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
                     MeasureSpec.makeMeasureSpec(taskRect.height(), MeasureSpec.AT_MOST));
         }
 
+        Rect stackRect = mTaskStackView.mLayoutAlgorithm.mCurrentStackRect;
+        measureChild(mHistoryButton,
+                MeasureSpec.makeMeasureSpec(stackRect.width(), MeasureSpec.EXACTLY),
+                heightMeasureSpec);
         setMeasuredDimension(width, height);
     }
 
@@ -330,6 +381,11 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
                     top + mDragView.getMeasuredHeight());
         }
 
+        Rect stackRect = mTaskStackView.mLayoutAlgorithm.mCurrentStackRect;
+        mHistoryButton.layout(stackRect.left, stackRect.top,
+                stackRect.left + mHistoryButton.getMeasuredWidth(),
+                stackRect.top + mHistoryButton.getMeasuredHeight());
+
         if (mAwaitingFirstLayout) {
             mAwaitingFirstLayout = false;
 
@@ -346,7 +402,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mSystemInsets.set(insets.getSystemWindowInsets());
         requestLayout();
-        return insets.consumeSystemWindowInsets();
+        return insets;
     }
 
     @Override
@@ -492,6 +548,67 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
         animate().translationY(0f);
     }
 
+    public final void onBusEvent(ShowHistoryEvent event) {
+        // Hide the history button when the history view is shown
+        hideHistoryButton(mHistoryTransitionDuration);
+    }
+
+    public final void onBusEvent(HideHistoryEvent event) {
+        // Show the history button when the history view is hidden
+        showHistoryButton(mHistoryTransitionDuration);
+    }
+
+    public final void onBusEvent(ShowHistoryButtonEvent event) {
+        showHistoryButton(150);
+    }
+
+    public final void onBusEvent(HideHistoryButtonEvent event) {
+        hideHistoryButton(100);
+    }
+
+    public final void onBusEvent(DebugFlagsChangedEvent event) {
+        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        if (!debugFlags.isHistoryEnabled()) {
+            hideHistoryButton(100);
+        }
+    }
+
+    /**
+     * Shows the history button.
+     */
+    private void showHistoryButton(int duration) {
+        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        if (!debugFlags.isHistoryEnabled()) {
+            return;
+        }
+
+        mHistoryButton.setVisibility(View.VISIBLE);
+        mHistoryButton.animate()
+                .alpha(1f)
+                .setDuration(duration)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .withLayer()
+                .start();
+    }
+
+    /**
+     * Hides the history button.
+     */
+    private void hideHistoryButton(int duration) {
+        mHistoryButton.animate()
+                .alpha(0f)
+                .setDuration(duration)
+                .setInterpolator(mFastOutLinearInInterpolator)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mHistoryButton.setVisibility(View.INVISIBLE);
+                    }
+                })
+                .withLayer()
+                .start();
+    }
+
     /**
      * Updates the dock region to match the specified dock state.
      */
index 5d091b1..1acc943 100644 (file)
@@ -573,7 +573,7 @@ public class TaskStackLayoutAlgorithm {
                     (mCurrentStackRect.height() - mTaskRect.height()) / 2;
             y = centerYOffset + getYForDeltaP(p, 0);
             z = mMaxTranslationZ;
-            relP = p;
+            relP = 1f;
 
         } else {
             // Otherwise, update the task to the stack layout
index 67710bf..04a14e4 100644 (file)
@@ -42,8 +42,12 @@ import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
+import com.android.systemui.recents.events.activity.HideHistoryEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
+import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
+import com.android.systemui.recents.events.activity.ShowHistoryEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
@@ -82,6 +86,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     private final static String TAG = "TaskStackView";
     private final static boolean DEBUG = false;
 
+    // The thresholds at which to show/hide the history button.
+    private static final float SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
+    private static final float HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
+
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t,
@@ -1017,6 +1025,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                     false /* requestViewFocus */);
         }
 
+        // Update the history button visibility
+        if (mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
+            EventBus.getDefault().send(new ShowHistoryButtonEvent());
+        }
+
         // Start dozing
         mUIDozeTrigger.startDozing();
     }
@@ -1333,10 +1346,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
 
     @Override
-    public void onScrollChanged(float p) {
+    public void onScrollChanged(float prevScroll, float curScroll) {
         mUIDozeTrigger.poke();
         requestSynchronizeStackViewsWithModel();
         postInvalidateOnAnimation();
+
+        if (prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
+                curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
+            EventBus.getDefault().send(new ShowHistoryButtonEvent());
+        } else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
+                curScroll >= HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD) {
+            EventBus.getDefault().send(new HideHistoryButtonEvent());
+        }
     }
 
     /**** EventBus Events ****/
@@ -1496,15 +1517,30 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         }
     }
 
+    public final void onBusEvent(ShowHistoryEvent event) {
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
+            tv.animate().alpha(0f).setDuration(200).start();
+        }
+    }
+
+    public final void onBusEvent(HideHistoryEvent event) {
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
+            tv.animate().alpha(1f).setDuration(200).start();
+        }
+    }
+
     /**
      * Removes the task from the stack, and updates the focus to the next task in the stack if the
      * removed TaskView was focused.
      */
     private void removeTaskViewFromStack(TaskView tv) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
         Task task = tv.getTask();
-        int taskIndex = mStack.indexOfTask(task);
-        boolean taskWasFocused = tv.isFocusedTask();
 
         // Reset the previously focused task before it is removed from the stack
         resetFocusedTask();
index 62b640e..90b73fe 100644 (file)
@@ -35,7 +35,7 @@ public class TaskStackViewScroller {
     private static final boolean DEBUG = false;
 
     public interface TaskStackViewScrollerCallbacks {
-        void onScrollChanged(float p);
+        void onScrollChanged(float prevScroll, float curScroll);
     }
 
     Context mContext;
@@ -78,9 +78,10 @@ public class TaskStackViewScroller {
 
     /** Sets the current stack scroll */
     public void setStackScroll(float s) {
+        float prevStackScroll = mStackScrollP;
         mStackScrollP = s;
         if (mCb != null) {
-            mCb.onScrollChanged(mStackScrollP);
+            mCb.onScrollChanged(prevStackScroll, mStackScrollP);
         }
     }
 
index 523f84f..44985d4 100644 (file)
@@ -71,7 +71,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
     ObjectAnimator mTaskProgressAnimator;
     float mMaxDimScale;
     int mDimAlpha;
-    AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(1f);
+    AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f);
     PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
     Paint mDimLayerPaint = new Paint();
     float mActionButtonTranslationZ;
@@ -265,15 +265,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
         toTransform.translationZ = 0;
     }
 
-    /**
-     * When we are un/filtering, this method will setup the transform that we are animating from,
-     * in order to show the task.
-     */
-    void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
-        // Fade the view in
-        fromTransform.alpha = 0f;
-    }
-
     /** Prepares this task view for the enter-recents animations.  This is called earlier in the
      * first layout because the actual animation into recents may take a long time. */
     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean hideTask,
@@ -617,12 +608,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
 
     /** Compute the dim as a function of the scale of this view. */
     int getDimFromTaskProgress() {
-        // TODO: Temporarily disable the dim on the stack
-        /*
-        float dim = mMaxDimScale * mDimInterpolator.getInterpolation(1f - mTaskProgress);
+        float x = mTaskProgress < 0 ? 1f : mDimInterpolator.getInterpolation(1f - mTaskProgress);
+        float dim = mMaxDimScale * x;
         return (int) (dim * 255);
-        */
-        return 0;
     }
 
     /** Update the dim as a function of the scale of this view. */
index fdc2543..9cf64d3 100644 (file)
@@ -37,7 +37,10 @@ LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUITests
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target Keyguard
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    mockito-target \
+    Keyguard \
+    android-support-v7-recyclerview
 
 # sign this with platform cert, so this test is allowed to inject key events into
 # UI it doesn't own. This is necessary to allow screenshots to be taken