summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorMichael Jurka <mikejurka@google.com>2012-02-14 13:57:14 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-02-14 13:57:14 -0800
commita17a7953f9385155e2d0d7b24d1395ed49147da3 (patch)
tree23333a8afd9849756fbc42828a6fb6c62b767d5e /packages
parent0599d6ede37304bf8f9ecd90dadea7707c160cd8 (diff)
parent99a9655b9333c3bff6e462b12baa56a5fcd4cb20 (diff)
downloadframeworks_base-a17a7953f9385155e2d0d7b24d1395ed49147da3.zip
frameworks_base-a17a7953f9385155e2d0d7b24d1395ed49147da3.tar.gz
frameworks_base-a17a7953f9385155e2d0d7b24d1395ed49147da3.tar.bz2
Merge "Making recents faster"
Diffstat (limited to 'packages')
-rw-r--r--packages/SystemUI/res/layout-land/status_bar_recent_item.xml1
-rw-r--r--packages/SystemUI/res/layout-port/status_bar_recent_item.xml1
-rw-r--r--packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/Choreographer.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java273
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java199
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java156
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java6
11 files changed, 518 insertions, 220 deletions
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 2d76455..aa27861 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -58,6 +58,7 @@
android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
android:scaleType="centerInside"
android:adjustViewBounds="true"
+ android:visibility="invisible"
/>
<TextView android:id="@+id/app_label"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index b653fcd..bc389f9 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -81,6 +81,7 @@
android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
android:scaleType="centerInside"
android:adjustViewBounds="true"
+ android:visibility="invisible"
/>
<TextView android:id="@+id/app_description"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index cb26db00..333fcda 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -65,6 +65,7 @@
android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
android:scaleType="centerInside"
android:adjustViewBounds="true"
+ android:visibility="invisible"
/>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 14ce266..cd8bd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -236,6 +236,10 @@ public class SwipeHelper {
public void onAnimationEnd(Animator animation) {
mCallback.onChildDismissed(view);
animView.setLayerType(View.LAYER_TYPE_NONE, null);
+ // Restore the alpha/translation parameters to what they were before swiping
+ // (for when these items are recycled)
+ animView.setAlpha(1f);
+ setTranslation(animView, 0f);
}
});
anim.addUpdateListener(new AnimatorUpdateListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index ad38a11..f8a4592 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -134,6 +134,7 @@ import android.view.View;
void jumpTo(boolean appearing) {
mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
+ mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
}
public void setPanelHeight(int h) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 4145fc4..92f4ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -16,12 +16,6 @@
package com.android.systemui.recent;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -36,15 +30,17 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Process;
-import android.os.SystemClock;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.LruCache;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.TabletStatusBar;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
public class RecentTasksLoader {
static final String TAG = "RecentTasksLoader";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -55,11 +51,14 @@ public class RecentTasksLoader {
private Context mContext;
private RecentsPanelView mRecentsPanel;
- private AsyncTask<Void, Integer, Void> mThumbnailLoader;
+ private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
+ private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
private final Handler mHandler;
private int mIconDpi;
private Bitmap mDefaultThumbnailBackground;
+ private Bitmap mDefaultIconBackground;
+ private int mNumTasksInFirstScreenful;
public RecentTasksLoader(Context context) {
mContext = context;
@@ -76,12 +75,20 @@ public class RecentTasksLoader {
mIconDpi = res.getDisplayMetrics().densityDpi;
}
+ // Render default icon (just a blank image)
+ int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
+ int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
+ mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+
// Render the default thumbnail background
- int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
- int height = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
+ int thumbnailWidth =
+ (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+ int thumbnailHeight =
+ (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
- mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ mDefaultThumbnailBackground =
+ Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mDefaultThumbnailBackground);
c.drawColor(color);
@@ -95,12 +102,17 @@ public class RecentTasksLoader {
public void setRecentsPanel(RecentsPanelView recentsPanel) {
mRecentsPanel = recentsPanel;
+ mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
}
public Bitmap getDefaultThumbnail() {
return mDefaultThumbnailBackground;
}
+ public Bitmap getDefaultIcon() {
+ return mDefaultIconBackground;
+ }
+
// Create an TaskDescription, returning null if the title or icon is null, or if it's the
// home activity
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
@@ -114,6 +126,12 @@ public class RecentTasksLoader {
homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
}
+ // Don't load the current home activity.
+ if (homeInfo != null
+ && homeInfo.packageName.equals(intent.getComponent().getPackageName())
+ && homeInfo.name.equals(intent.getComponent().getClassName())) {
+ return null;
+ }
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -121,9 +139,8 @@ public class RecentTasksLoader {
if (resolveInfo != null) {
final ActivityInfo info = resolveInfo.activityInfo;
final String title = info.loadLabel(pm).toString();
- Drawable icon = getFullResIcon(resolveInfo, pm);
- if (title != null && title.length() > 0 && icon != null) {
+ if (title != null && title.length() > 0) {
if (DEBUG) Log.v(TAG, "creating activity desc for id="
+ persistentTaskId + ", label=" + title);
@@ -131,14 +148,6 @@ public class RecentTasksLoader {
persistentTaskId, resolveInfo, baseIntent, info.packageName,
description);
item.setLabel(title);
- item.setIcon(icon);
-
- // Don't load the current home activity.
- if (homeInfo != null
- && homeInfo.packageName.equals(intent.getComponent().getPackageName())
- && homeInfo.name.equals(intent.getComponent().getClassName())) {
- return null;
- }
return item;
} else {
@@ -148,10 +157,12 @@ public class RecentTasksLoader {
return null;
}
- void loadThumbnail(TaskDescription td) {
+ void loadThumbnailAndIcon(TaskDescription td) {
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ final PackageManager pm = mContext.getPackageManager();
ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId);
+ Drawable icon = getFullResIcon(td.resolveInfo, pm);
if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
+ td + ": " + thumbs.mainThumbnail);
@@ -161,6 +172,10 @@ public class RecentTasksLoader {
} else {
td.setThumbnail(mDefaultThumbnailBackground);
}
+ if (icon != null) {
+ td.setIcon(icon);
+ }
+ td.setLoaded(true);
}
}
@@ -194,111 +209,149 @@ public class RecentTasksLoader {
return getFullResDefaultActivityIcon();
}
- public void cancelLoadingThumbnails() {
+ public void cancelLoadingThumbnailsAndIcons() {
+ if (mTaskLoader != null) {
+ mTaskLoader.cancel(false);
+ mTaskLoader = null;
+ }
if (mThumbnailLoader != null) {
mThumbnailLoader.cancel(false);
mThumbnailLoader = null;
}
}
- // return a snapshot of the current list of recent apps
- ArrayList<TaskDescription> getRecentTasks() {
- cancelLoadingThumbnails();
-
- ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
- final PackageManager pm = mContext.getPackageManager();
- final ActivityManager am = (ActivityManager)
+ public void loadTasksInBackground() {
+ // cancel all previous loading of tasks and thumbnails
+ cancelLoadingThumbnailsAndIcons();
+ final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
+ new LinkedBlockingQueue<TaskDescription>();
+ final ArrayList<TaskDescription> taskDescriptionsWaitingToLoad =
+ new ArrayList<TaskDescription>();
+ mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
+ @Override
+ protected void onProgressUpdate(ArrayList<TaskDescription>... values) {
+ if (!isCancelled()) {
+ ArrayList<TaskDescription> newTasks = values[0];
+ // do a callback to RecentsPanelView to let it know we have more values
+ // how do we let it know we're all done? just always call back twice
+ mRecentsPanel.onTasksLoaded(newTasks);
+ }
+ }
+ @Override
+ protected Void doInBackground(Void... params) {
+ // We load in two stages: first, we update progress with just the first screenful
+ // of items. Then, we update with the rest of the items
+ final int origPri = Process.getThreadPriority(Process.myTid());
+ Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ final PackageManager pm = mContext.getPackageManager();
+ final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
- final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+ final List<ActivityManager.RecentTaskInfo> recentTasks =
+ am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+ int numTasks = recentTasks.size();
+ ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
- ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
- .resolveActivityInfo(pm, 0);
+ boolean firstScreenful = true;
+ ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
- HashSet<Integer> recentTasksToKeepInCache = new HashSet<Integer>();
- int numTasks = recentTasks.size();
+ // skip the first task - assume it's either the home screen or the current activity.
+ final int first = 1;
+ for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
+ if (isCancelled()) {
+ break;
+ }
+ final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+ TaskDescription item = createTaskDescription(recentInfo.id,
+ recentInfo.persistentId, recentInfo.baseIntent,
+ recentInfo.origActivity, recentInfo.description, homeInfo);
+
+ if (item != null) {
+ while (true) {
+ try {
+ tasksWaitingForThumbnails.put(item);
+ break;
+ } catch (InterruptedException e) {
+ }
+ }
+ tasks.add(item);
+ if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) {
+ publishProgress(tasks);
+ tasks = new ArrayList<TaskDescription>();
+ firstScreenful = false;
+ //break;
+ }
+ ++index;
+ }
+ }
- // skip the first task - assume it's either the home screen or the current activity.
- final int first = 1;
- recentTasksToKeepInCache.add(recentTasks.get(0).persistentId);
- for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
- final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+ if (!isCancelled()) {
+ publishProgress(tasks);
+ if (firstScreenful) {
+ // always should publish two updates
+ publishProgress(new ArrayList<TaskDescription>());
+ }
+ }
- TaskDescription item = createTaskDescription(recentInfo.id,
- recentInfo.persistentId, recentInfo.baseIntent,
- recentInfo.origActivity, recentInfo.description, homeInfo);
+ while (true) {
+ try {
+ tasksWaitingForThumbnails.put(new TaskDescription());
+ break;
+ } catch (InterruptedException e) {
+ }
+ }
- if (item != null) {
- tasks.add(item);
- ++index;
+ Process.setThreadPriority(origPri);
+ return null;
}
- }
-
- // when we're not using the TaskDescription cache, we load the thumbnails in the
- // background
- loadThumbnailsInBackground(new ArrayList<TaskDescription>(tasks));
- return tasks;
+ };
+ mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails);
}
- private void loadThumbnailsInBackground(final ArrayList<TaskDescription> descriptions) {
- if (descriptions.size() > 0) {
- if (DEBUG) Log.v(TAG, "Showing " + descriptions.size() + " tasks");
- loadThumbnail(descriptions.get(0));
- if (descriptions.size() > 1) {
- mThumbnailLoader = new AsyncTask<Void, Integer, Void>() {
- @Override
- protected void onProgressUpdate(Integer... values) {
- final TaskDescription td = descriptions.get(values[0]);
- if (!isCancelled()) {
- mRecentsPanel.onTaskThumbnailLoaded(td);
- }
- // This is to prevent the loader thread from getting ahead
- // of our UI updates.
- mHandler.post(new Runnable() {
- @Override public void run() {
- synchronized (td) {
- td.notifyAll();
- }
- }
- });
+ private void loadThumbnailsAndIconsInBackground(
+ final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) {
+ // continually read items from tasksWaitingForThumbnails and load
+ // thumbnails and icons for them. finish thread when cancelled or there
+ // is a null item in tasksWaitingForThumbnails
+ mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() {
+ @Override
+ protected void onProgressUpdate(TaskDescription... values) {
+ if (!isCancelled()) {
+ TaskDescription td = values[0];
+ mRecentsPanel.onTaskThumbnailLoaded(td);
+ }
+ }
+ @Override
+ protected Void doInBackground(Void... params) {
+ final int origPri = Process.getThreadPriority(Process.myTid());
+ Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+
+ while (true) {
+ if (isCancelled()) {
+ break;
}
-
- @Override
- protected Void doInBackground(Void... params) {
- final int origPri = Process.getThreadPriority(Process.myTid());
- Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
- long nextTime = SystemClock.uptimeMillis();
- for (int i=1; i<descriptions.size(); i++) {
- TaskDescription td = descriptions.get(i);
- loadThumbnail(td);
- long now = SystemClock.uptimeMillis();
- nextTime += 0;
- if (nextTime > now) {
- try {
- Thread.sleep(nextTime-now);
- } catch (InterruptedException e) {
- }
- }
-
- if (isCancelled()) {
- break;
- }
- synchronized (td) {
- publishProgress(i);
- try {
- td.wait(500);
- } catch (InterruptedException e) {
- }
- }
+ TaskDescription td = null;
+ while (td == null) {
+ try {
+ td = tasksWaitingForThumbnails.take();
+ } catch (InterruptedException e) {
}
- Process.setThreadPriority(origPri);
- return null;
}
- };
- mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ if (td.isNull()) {
+ break;
+ }
+ loadThumbnailAndIcon(td);
+ synchronized(td) {
+ publishProgress(td);
+ }
+ }
+
+ Process.setThreadPriority(origPri);
+ return null;
}
- }
+ };
+ mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index f971d2d..4718a17 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -22,11 +22,18 @@ import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
+import android.view.View.MeasureSpec;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
@@ -34,6 +41,8 @@ import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
+import java.util.ArrayList;
+
public class RecentsHorizontalScrollView extends HorizontalScrollView
implements SwipeHelper.Callback {
private static final String TAG = RecentsPanelView.TAG;
@@ -44,6 +53,8 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private ArrayList<View> mRecycledViews;
+ private int mNumItemsInOneScreenful;
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
@@ -51,6 +62,7 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+ mRecycledViews = new ArrayList<View>();
}
private int scrollPositionOfMostRecent() {
@@ -58,9 +70,23 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
}
private void update() {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ mRecycledViews.add(v);
+ mAdapter.recycleView(v);
+ }
+ LayoutTransition transitioner = getLayoutTransition();
+ setLayoutTransition(null);
+
mLinearLayout.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
- final View view = mAdapter.getView(i, null, mLinearLayout);
+ View old = null;
+ if (mRecycledViews.size() != 0) {
+ old = mRecycledViews.remove(mRecycledViews.size() - 1);
+ old.setVisibility(VISIBLE);
+ }
+
+ final View view = mAdapter.getView(i, old, mLinearLayout);
if (mPerformanceHelper != null) {
mPerformanceHelper.addViewCallback(view);
@@ -87,7 +113,8 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
}
};
- final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
+ final View thumbnailView = holder.thumbnailView;
OnLongClickListener longClickListener = new OnLongClickListener() {
public boolean onLongClick(View v) {
final View anchorView = view.findViewById(R.id.app_description);
@@ -107,13 +134,21 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
appTitle.setOnTouchListener(noOpListener);
mLinearLayout.addView(view);
}
+ setLayoutTransition(transitioner);
+
// Scroll to end after layout.
- post(new Runnable() {
- public void run() {
- mLastScrollPosition = scrollPositionOfMostRecent();
- scrollTo(mLastScrollPosition, 0);
- }
- });
+ final ViewTreeObserver observer = getViewTreeObserver();
+
+ final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(mLastScrollPosition, 0);
+ if (observer.isAlive()) {
+ observer.removeOnGlobalLayoutListener(this);
+ }
+ }
+ };
+ observer.addOnGlobalLayoutListener(updateScroll);
}
@Override
@@ -142,8 +177,10 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
}
public void onChildDismissed(View v) {
+ mRecycledViews.add(v);
mLinearLayout.removeView(v);
mCallback.handleSwipe(v);
+ v.setActivated(false);
}
public void onBeginDrag(View v) {
@@ -315,6 +352,24 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
update();
}
});
+ DisplayMetrics dm = getResources().getDisplayMetrics();
+ int childWidthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
+ int childheightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
+ View child = mAdapter.createView(mLinearLayout);
+ child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+ mNumItemsInOneScreenful =
+ (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth());
+ mRecycledViews.add(child);
+
+ for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
+ mRecycledViews.add(mAdapter.createView(mLinearLayout));
+ }
+ }
+
+ public int numItemsInOneScreenful() {
+ return mNumItemsInOneScreenful;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index a10e363..8706f10 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -27,6 +27,7 @@ import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.Settings;
import android.util.AttributeSet;
@@ -36,18 +37,18 @@ import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.PopupMenu;
-import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
@@ -59,7 +60,7 @@ import com.android.systemui.statusbar.tablet.TabletStatusBar;
import java.util.ArrayList;
-public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback,
+public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -71,6 +72,10 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
private StatusBarTouchProxy mStatusBarTouchProxy;
private boolean mShowing;
+ private boolean mWaitingToShow;
+ private boolean mWaitingToShowAnimated;
+ private boolean mReadyToShow;
+ private int mNumItemsWaitingForThumbnailsAndIcons;
private Choreographer mChoreo;
OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
@@ -104,6 +109,7 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
TextView labelView;
TextView descriptionView;
TaskDescription taskDescription;
+ boolean loadedThumbnailAndIcon;
}
/* package */ final class TaskDescriptionAdapter extends BaseAdapter {
@@ -125,42 +131,82 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
return position; // we just need something unique for this position
}
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
- if (convertView == null) {
- convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
- holder = new ViewHolder();
- holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
- holder.thumbnailViewImage = (ImageView) convertView.findViewById(
- R.id.app_thumbnail_image);
- // If we set the default thumbnail now, we avoid an onLayout when we update
- // the thumbnail later (if they both have the same dimensions)
+ public View createView(ViewGroup parent) {
+ View convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
+ ViewHolder holder = new ViewHolder();
+ holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
+ holder.thumbnailViewImage =
+ (ImageView) convertView.findViewById(R.id.app_thumbnail_image);
+ // If we set the default thumbnail now, we avoid an onLayout when we update
+ // the thumbnail later (if they both have the same dimensions)
+ if (mRecentTasksLoader != null) {
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
+ }
+ holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
+ if (mRecentTasksLoader != null) {
+ holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ }
+ holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
+ holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
- holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
- holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
+ convertView.setTag(holder);
+ return convertView;
+ }
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = createView(parent);
}
+ ViewHolder holder = (ViewHolder) convertView.getTag();
// index is reverse since most recent appears at the bottom...
final int index = mRecentTaskDescriptions.size() - position - 1;
final TaskDescription td = mRecentTaskDescriptions.get(index);
- holder.iconView.setImageDrawable(td.getIcon());
+
holder.labelView.setText(td.getLabel());
holder.thumbnailView.setContentDescription(td.getLabel());
- updateThumbnail(holder, td.getThumbnail(), true, false);
+ holder.loadedThumbnailAndIcon = td.isLoaded();
+ if (td.isLoaded()) {
+ updateThumbnail(holder, td.getThumbnail(), true, false);
+ updateIcon(holder, td.getIcon(), true, false);
+ mNumItemsWaitingForThumbnailsAndIcons--;
+ }
holder.thumbnailView.setTag(td);
holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
holder.taskDescription = td;
-
return convertView;
}
+
+ public void recycleView(View v) {
+ ViewHolder holder = (ViewHolder) v.getTag();
+ updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
+ holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setVisibility(INVISIBLE);
+ holder.labelView.setText(null);
+ holder.thumbnailView.setContentDescription(null);
+ holder.thumbnailView.setTag(null);
+ holder.thumbnailView.setOnLongClickListener(null);
+ holder.thumbnailView.setVisibility(INVISIBLE);
+ holder.taskDescription = null;
+ holder.loadedThumbnailAndIcon = false;
+ }
+ }
+
+ public int numItemsInOneScreenful() {
+ if (mRecentsContainer instanceof RecentsHorizontalScrollView){
+ RecentsHorizontalScrollView scrollView
+ = (RecentsHorizontalScrollView) mRecentsContainer;
+ return scrollView.numItemsInOneScreenful();
+ } else if (mRecentsContainer instanceof RecentsVerticalScrollView){
+ RecentsVerticalScrollView scrollView
+ = (RecentsVerticalScrollView) mRecentsContainer;
+ return scrollView.numItemsInOneScreenful();
+ }
+ else {
+ throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
+ }
}
@Override
@@ -192,15 +238,31 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
}
public void show(boolean show, boolean animate) {
- show(show, animate, null);
+ if (show) {
+ mWaitingToShow = true;
+ mWaitingToShowAnimated = animate;
+ showIfReady();
+ } else {
+ show(show, animate, null, false);
+ }
+ }
+
+ private void showIfReady() {
+ // mWaitingToShow = there was a touch up on the recents button
+ // mReadyToShow = we've created views for the first screenful of items
+ if (mWaitingToShow && mReadyToShow) { // && mNumItemsWaitingForThumbnailsAndIcons <= 0
+ show(true, mWaitingToShowAnimated, null, false);
+ }
}
public void show(boolean show, boolean animate,
- ArrayList<TaskDescription> recentTaskDescriptions) {
+ ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
+ // For now, disable animations. We may want to re-enable in the future
+ animate = false;
if (show) {
// Need to update list of recent apps before we set visibility so this view's
// content description is updated before it gets focus for TalkBack mode
- refreshRecentTasksList(recentTaskDescriptions);
+ refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
// if there are no apps, either bring up a "No recent apps" message, or just
// quit early
@@ -209,19 +271,24 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
} else {
if (noApps) {
- if (DEBUG) Log.v(TAG, "Nothing to show");
+ if (DEBUG) Log.v(TAG, "Nothing to show");
// Need to set recent tasks to dirty so that next time we load, we
// refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnails();
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTasksDirty = true;
+
+ mWaitingToShow = false;
+ mReadyToShow = false;
return;
}
}
} else {
// Need to set recent tasks to dirty so that next time we load, we
// refresh the list of tasks
- mRecentTasksLoader.cancelLoadingThumbnails();
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTasksDirty = true;
+ mWaitingToShow = false;
+ mReadyToShow = false;
}
if (animate) {
if (mShowing != show) {
@@ -385,7 +452,6 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
}
-
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
@@ -425,6 +491,20 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
}
}
+
+ private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) {
+ if (icon != null) {
+ h.iconView.setImageDrawable(icon);
+ if (show && h.iconView.getVisibility() != View.VISIBLE) {
+ if (anim) {
+ h.iconView.setAnimation(
+ AnimationUtils.loadAnimation(mContext, R.anim.recent_appear));
+ }
+ h.iconView.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
if (thumbnail != null) {
// Should remove the default image in the frame
@@ -458,31 +538,36 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
}
}
- void onTaskThumbnailLoaded(TaskDescription ad) {
- synchronized (ad) {
+ void onTaskThumbnailLoaded(TaskDescription td) {
+ synchronized (td) {
if (mRecentsContainer != null) {
ViewGroup container = mRecentsContainer;
if (container instanceof HorizontalScrollView
|| container instanceof ScrollView) {
- container = (ViewGroup)container.findViewById(
+ container = (ViewGroup) container.findViewById(
R.id.recents_linear_layout);
}
// Look for a view showing this thumbnail, to update.
- for (int i=0; i<container.getChildCount(); i++) {
+ for (int i=0; i < container.getChildCount(); i++) {
View v = container.getChildAt(i);
if (v.getTag() instanceof ViewHolder) {
ViewHolder h = (ViewHolder)v.getTag();
- if (h.taskDescription == ad) {
+ if (!h.loadedThumbnailAndIcon && h.taskDescription == td) {
// only fade in the thumbnail if recents is already visible-- we
// show it immediately otherwise
- boolean animateShow = mShowing &&
- mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
- updateThumbnail(h, ad.getThumbnail(), true, animateShow);
+ //boolean animateShow = mShowing &&
+ // mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
+ boolean animateShow = false;
+ updateIcon(h, td.getIcon(), true, animateShow);
+ updateThumbnail(h, td.getThumbnail(), true, animateShow);
+ h.loadedThumbnailAndIcon = true;
+ mNumItemsWaitingForThumbnailsAndIcons--;
}
}
}
}
- }
+ }
+ showIfReady();
}
// additional optimization when we have sofware system buttons - start loading the recent
@@ -516,7 +601,7 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
public void clearRecentTasksList() {
// Clear memory used by screenshots
if (mRecentTaskDescriptions != null) {
- mRecentTasksLoader.cancelLoadingThumbnails();
+ mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTaskDescriptions.clear();
mListAdapter.notifyDataSetInvalidated();
mRecentTasksDirty = true;
@@ -524,26 +609,50 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe
}
public void refreshRecentTasksList() {
- refreshRecentTasksList(null);
+ refreshRecentTasksList(null, false);
}
- private void refreshRecentTasksList(ArrayList<TaskDescription> recentTasksList) {
+ private void refreshRecentTasksList(
+ ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
if (mRecentTasksDirty) {
if (recentTasksList != null) {
- mRecentTaskDescriptions = recentTasksList;
+ mFirstScreenful = true;
+ onTasksLoaded(recentTasksList);
} else {
- mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
+ mFirstScreenful = true;
+ mRecentTasksLoader.loadTasksInBackground();
}
- mListAdapter.notifyDataSetInvalidated();
- updateUiElements(getResources().getConfiguration());
mRecentTasksDirty = false;
}
}
+ boolean mFirstScreenful;
+ public void onTasksLoaded(ArrayList<TaskDescription> tasks) {
+ if (!mFirstScreenful && tasks.size() == 0) {
+ return;
+ }
+ mNumItemsWaitingForThumbnailsAndIcons =
+ mFirstScreenful ? tasks.size() : mRecentTaskDescriptions.size();
+ if (mRecentTaskDescriptions == null) {
+ mRecentTaskDescriptions = new ArrayList(tasks);
+ } else {
+ mRecentTaskDescriptions.addAll(tasks);
+ }
+ mListAdapter.notifyDataSetInvalidated();
+ updateUiElements(getResources().getConfiguration());
+ mReadyToShow = true;
+ mFirstScreenful = false;
+ showIfReady();
+ }
+
public ArrayList<TaskDescription> getRecentTasksList() {
return mRecentTaskDescriptions;
}
+ public boolean getFirstScreenful() {
+ return mFirstScreenful;
+ }
+
private void updateUiElements(Configuration config) {
final int items = mRecentTaskDescriptions.size();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index dc13092..0605c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -22,10 +22,18 @@ import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.LinearLayout;
import android.widget.ScrollView;
@@ -33,6 +41,8 @@ import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
+import java.util.ArrayList;
+
public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper.Callback {
private static final String TAG = RecentsPanelView.TAG;
private static final boolean DEBUG = RecentsPanelView.DEBUG;
@@ -42,6 +52,8 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper
protected int mLastScrollPosition;
private SwipeHelper mSwipeHelper;
private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+ private ArrayList<View> mRecycledViews;
+ private int mNumItemsInOneScreenful;
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
@@ -50,6 +62,7 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+ mRecycledViews = new ArrayList<View>();
}
private int scrollPositionOfMostRecent() {
@@ -57,77 +70,91 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper
}
private void update() {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View v = mLinearLayout.getChildAt(i);
+ mRecycledViews.add(v);
+ mAdapter.recycleView(v);
+ }
+ LayoutTransition transitioner = getLayoutTransition();
+ setLayoutTransition(null);
+
mLinearLayout.removeAllViews();
// Once we can clear the data associated with individual item views,
// we can get rid of the removeAllViews() and the code below will
// recycle them.
for (int i = 0; i < mAdapter.getCount(); i++) {
View old = null;
- if (i < mLinearLayout.getChildCount()) {
- old = mLinearLayout.getChildAt(i);
- old.setVisibility(View.VISIBLE);
+ if (mRecycledViews.size() != 0) {
+ old = mRecycledViews.remove(mRecycledViews.size() - 1);
+ old.setVisibility(VISIBLE);
}
+
final View view = mAdapter.getView(i, old, mLinearLayout);
if (mPerformanceHelper != null) {
mPerformanceHelper.addViewCallback(view);
}
- if (old == null) {
- OnTouchListener noOpListener = new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return true;
- }
- };
+ OnTouchListener noOpListener = new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return true;
+ }
+ };
- view.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- mCallback.dismiss();
- }
- });
- // We don't want a click sound when we dimiss recents
- view.setSoundEffectsEnabled(false);
+ view.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ mCallback.dismiss();
+ }
+ });
+ // We don't want a click sound when we dimiss recents
+ view.setSoundEffectsEnabled(false);
- OnClickListener launchAppListener = new OnClickListener() {
- public void onClick(View v) {
- mCallback.handleOnClick(view);
- }
- };
-
- final View thumbnailView = view.findViewById(R.id.app_thumbnail);
- OnLongClickListener longClickListener = new OnLongClickListener() {
- public boolean onLongClick(View v) {
- final View anchorView = view.findViewById(R.id.app_description);
- mCallback.handleLongPress(view, anchorView, thumbnailView);
- return true;
- }
- };
- thumbnailView.setClickable(true);
- thumbnailView.setOnClickListener(launchAppListener);
- thumbnailView.setOnLongClickListener(longClickListener);
-
- // We don't want to dismiss recents if a user clicks on the app title
- // (we also don't want to launch the app either, though, because the
- // app title is a small target and doesn't have great click feedback)
- final View appTitle = view.findViewById(R.id.app_label);
- appTitle.setContentDescription(" ");
- appTitle.setOnTouchListener(noOpListener);
- final View calloutLine = view.findViewById(R.id.recents_callout_line);
- calloutLine.setOnTouchListener(noOpListener);
- mLinearLayout.addView(view);
- }
- }
- for (int i = mAdapter.getCount(); i < mLinearLayout.getChildCount(); i++) {
- mLinearLayout.getChildAt(i).setVisibility(View.GONE);
+ OnClickListener launchAppListener = new OnClickListener() {
+ public void onClick(View v) {
+ mCallback.handleOnClick(view);
+ }
+ };
+
+ RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
+ final View thumbnailView = holder.thumbnailView;
+ OnLongClickListener longClickListener = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = view.findViewById(R.id.app_description);
+ mCallback.handleLongPress(view, anchorView, thumbnailView);
+ return true;
+ }
+ };
+ thumbnailView.setClickable(true);
+ thumbnailView.setOnClickListener(launchAppListener);
+ thumbnailView.setOnLongClickListener(longClickListener);
+
+ // We don't want to dismiss recents if a user clicks on the app title
+ // (we also don't want to launch the app either, though, because the
+ // app title is a small target and doesn't have great click feedback)
+ final View appTitle = view.findViewById(R.id.app_label);
+ appTitle.setContentDescription(" ");
+ appTitle.setOnTouchListener(noOpListener);
+ final View calloutLine = view.findViewById(R.id.recents_callout_line);
+ calloutLine.setOnTouchListener(noOpListener);
+
+ mLinearLayout.addView(view);
}
+ setLayoutTransition(transitioner);
+
// Scroll to end after layout.
- post(new Runnable() {
- public void run() {
- mLastScrollPosition = scrollPositionOfMostRecent();
- scrollTo(0, mLastScrollPosition);
- }
- });
+ final ViewTreeObserver observer = getViewTreeObserver();
+
+ final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(0, mLastScrollPosition);
+ if (observer.isAlive()) {
+ observer.removeOnGlobalLayoutListener(this);
+ }
+ }
+ };
+ observer.addOnGlobalLayoutListener(updateScroll);
}
@Override
@@ -156,8 +183,10 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper
}
public void onChildDismissed(View v) {
+ mRecycledViews.add(v);
mLinearLayout.removeView(v);
mCallback.handleSwipe(v);
+ v.setActivated(false);
}
public void onBeginDrag(View v) {
@@ -330,6 +359,25 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper
update();
}
});
+
+ DisplayMetrics dm = getResources().getDisplayMetrics();
+ int childWidthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
+ int childheightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
+ View child = mAdapter.createView(mLinearLayout);
+ child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+ mNumItemsInOneScreenful =
+ (int) FloatMath.ceil(dm.heightPixels / (float) child.getMeasuredHeight());
+ mRecycledViews.add(child);
+
+ for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
+ mRecycledViews.add(mAdapter.createView(mLinearLayout));
+ }
+ }
+
+ public int numItemsInOneScreenful() {
+ return mNumItemsInOneScreenful;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index dcfd6d8..7e979b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -32,6 +32,7 @@ public final class TaskDescription {
private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
private Drawable mIcon; // application package icon
private CharSequence mLabel; // application package label
+ private boolean mLoaded;
public TaskDescription(int _taskId, int _persistentTaskId,
ResolveInfo _resolveInfo, Intent _intent,
@@ -45,6 +46,28 @@ public final class TaskDescription {
packageName = _packageName;
}
+ public TaskDescription() {
+ resolveInfo = null;
+ intent = null;
+ taskId = -1;
+ persistentTaskId = -1;
+
+ description = null;
+ packageName = null;
+ }
+
+ public void setLoaded(boolean loaded) {
+ mLoaded = loaded;
+ }
+
+ public boolean isLoaded() {
+ return mLoaded;
+ }
+
+ public boolean isNull() {
+ return resolveInfo == null;
+ }
+
// mark all these as locked?
public CharSequence getLabel() {
return mLabel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5a1e3f4..b3cef90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -393,7 +393,7 @@ public class PhoneStatusBar extends StatusBar {
}
lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
lp.setTitle("RecentsPanel");
- lp.windowAnimations = R.style.Animation_RecentPanel;
+ lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
return lp;
@@ -403,11 +403,13 @@ public class PhoneStatusBar extends StatusBar {
// Recents Panel
boolean visible = false;
ArrayList<TaskDescription> recentTasksList = null;
+ boolean firstScreenful = false;
if (mRecentsPanel != null) {
visible = mRecentsPanel.isShowing();
WindowManagerImpl.getDefault().removeView(mRecentsPanel);
if (visible) {
recentTasksList = mRecentsPanel.getRecentTasksList();
+ firstScreenful = mRecentsPanel.getFirstScreenful();
}
}
@@ -425,7 +427,7 @@ public class PhoneStatusBar extends StatusBar {
WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
mRecentsPanel.setBar(this);
if (visible) {
- mRecentsPanel.show(true, false, recentTasksList);
+ mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
}
}