Skip to content

Commit 9a76aff

Browse files
mikejurkaAndroid (Google) Code Review
authored andcommitted
Merge "Make Recent Apps faster" into ics-mr0
2 parents 8408e51 + 412cba8 commit 9a76aff

File tree

8 files changed

+116
-70
lines changed

8 files changed

+116
-70
lines changed

packages/SystemUI/res/anim/recent_appear.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@
1616

1717
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
1818
android:fromAlpha="0.0" android:toAlpha="1.0"
19-
android:duration="@android:integer/config_mediumAnimTime"
19+
android:duration="@android:integer/config_shortAnimTime"
2020
/>

packages/SystemUI/res/layout-land/status_bar_recent_item.xml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939
android:layout_marginTop="@dimen/status_bar_recents_thumbnail_top_margin"
4040
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
4141
android:background="@drawable/recents_thumbnail_bg"
42-
android:foreground="@drawable/recents_thumbnail_fg">
42+
android:foreground="@drawable/recents_thumbnail_fg"
43+
android:visibility="invisible">
4344
<ImageView android:id="@+id/app_thumbnail_image"
4445
android:layout_width="@dimen/status_bar_recents_thumbnail_width"
4546
android:layout_height="@dimen/status_bar_recents_thumbnail_height"
46-
android:visibility="invisible"
4747
/>
4848
</FrameLayout>
4949

@@ -58,7 +58,6 @@
5858
android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
5959
android:scaleType="centerInside"
6060
android:adjustViewBounds="true"
61-
android:visibility="invisible"
6261
/>
6362

6463
<TextView android:id="@+id/app_label"
@@ -74,7 +73,6 @@
7473
android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
7574
android:singleLine="true"
7675
android:ellipsize="marquee"
77-
android:visibility="invisible"
7876
android:textColor="@color/status_bar_recents_app_label_color"
7977
/>
8078

packages/SystemUI/res/layout-port/status_bar_recent_item.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@
5252
android:layout_toRightOf="@id/app_label"
5353
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
5454
android:background="@drawable/recents_thumbnail_bg"
55-
android:foreground="@drawable/recents_thumbnail_fg">
55+
android:foreground="@drawable/recents_thumbnail_fg"
56+
android:visibility="invisible">
5657
<ImageView android:id="@+id/app_thumbnail_image"
5758
android:layout_width="@dimen/status_bar_recents_thumbnail_width"
5859
android:layout_height="@dimen/status_bar_recents_thumbnail_height"
59-
android:visibility="invisible"
6060
/>
6161
</FrameLayout>
6262
<View android:id="@+id/recents_callout_line"

packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
3232
android:scaleType="center"
3333
android:background="@drawable/recents_thumbnail_bg"
34-
android:foreground="@drawable/recents_thumbnail_fg">
34+
android:foreground="@drawable/recents_thumbnail_fg"
35+
android:visibility="invisible">
3536
<ImageView android:id="@+id/app_thumbnail_image"
3637
android:layout_width="@dimen/status_bar_recents_thumbnail_width"
3738
android:layout_height="@dimen/status_bar_recents_thumbnail_height"
38-
android:visibility="invisible"
3939
/>
4040
<ImageView android:id="@+id/app_icon"
4141
android:layout_width="wrap_content"

packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ public RecentTasksLoader(Context context) {
8686
mIconDpi = isTablet ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
8787

8888
// Render the default thumbnail background
89-
int width = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_width);
90-
int height = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_height);
89+
int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
90+
int height = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
9191
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
9292

9393
mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
@@ -106,6 +106,10 @@ public void setRecentsPanel(RecentsPanelView recentsPanel) {
106106
mRecentsPanel = recentsPanel;
107107
}
108108

109+
public Bitmap getDefaultThumbnail() {
110+
return mDefaultThumbnailBackground;
111+
}
112+
109113
// Create an TaskDescription, returning null if the title or icon is null, or if it's the
110114
// home activity
111115
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
@@ -278,7 +282,7 @@ protected Void doInBackground(Void... params) {
278282
TaskDescription td = descriptions.get(i);
279283
loadThumbnail(td);
280284
long now = SystemClock.uptimeMillis();
281-
nextTime += 150;
285+
nextTime += 0;
282286
if (nextTime > now) {
283287
try {
284288
Thread.sleep(nextTime-now);

packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java

Lines changed: 88 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import android.view.MenuItem;
3838
import android.view.MotionEvent;
3939
import android.view.View;
40+
import android.view.ViewConfiguration;
4041
import android.view.ViewGroup;
4142
import android.view.accessibility.AccessibilityEvent;
4243
import android.view.animation.AnimationUtils;
@@ -57,8 +58,8 @@
5758
import com.android.systemui.statusbar.tablet.StatusBarPanel;
5859
import com.android.systemui.statusbar.tablet.TabletStatusBar;
5960

60-
public class RecentsPanelView extends RelativeLayout
61-
implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener {
61+
public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback,
62+
StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
6263
static final String TAG = "RecentsPanelView";
6364
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
6465
private Context mContext;
@@ -74,6 +75,7 @@ public class RecentsPanelView extends RelativeLayout
7475

7576
private RecentTasksLoader mRecentTasksLoader;
7677
private ArrayList<TaskDescription> mRecentTaskDescriptions;
78+
private boolean mRecentTasksDirty = true;
7779
private TaskDescriptionAdapter mListAdapter;
7880
private int mThumbnailWidth;
7981

@@ -94,6 +96,7 @@ public boolean onLongClick(View v) {
9496
/* package */ final static class ViewHolder {
9597
View thumbnailView;
9698
ImageView thumbnailViewImage;
99+
Bitmap thumbnailViewImageBitmap;
97100
ImageView iconView;
98101
TextView labelView;
99102
TextView descriptionView;
@@ -127,6 +130,10 @@ public View getView(int position, View convertView, ViewGroup parent) {
127130
holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
128131
holder.thumbnailViewImage = (ImageView) convertView.findViewById(
129132
R.id.app_thumbnail_image);
133+
// If we set the default thumbnail now, we avoid an onLayout when we update
134+
// the thumbnail later (if they both have the same dimensions)
135+
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
136+
130137
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
131138
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
132139
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -139,12 +146,15 @@ public View getView(int position, View convertView, ViewGroup parent) {
139146
// index is reverse since most recent appears at the bottom...
140147
final int index = mRecentTaskDescriptions.size() - position - 1;
141148

142-
final TaskDescription taskDescription = mRecentTaskDescriptions.get(index);
143-
applyTaskDescription(holder, taskDescription, false);
149+
final TaskDescription td = mRecentTaskDescriptions.get(index);
150+
holder.iconView.setImageDrawable(td.getIcon());
151+
holder.labelView.setText(td.getLabel());
152+
holder.thumbnailView.setContentDescription(td.getLabel());
153+
updateThumbnail(holder, td.getThumbnail(), true, false);
144154

145-
holder.thumbnailView.setTag(taskDescription);
155+
holder.thumbnailView.setTag(td);
146156
holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
147-
holder.taskDescription = taskDescription;
157+
holder.taskDescription = td;
148158

149159
return convertView;
150160
}
@@ -193,6 +203,7 @@ public void show(boolean show, boolean animate,
193203
}
194204
} else {
195205
mRecentTasksLoader.cancelLoadingThumbnails();
206+
mRecentTasksDirty = true;
196207
}
197208
if (animate) {
198209
if (mShowing != show) {
@@ -250,9 +261,7 @@ public void onAnimationEnd(Animator animation) {
250261
createCustomAnimations(transitioner);
251262
} else {
252263
((ViewGroup)mRecentsContainer).setLayoutTransition(null);
253-
// Clear memory used by screenshots
254-
mRecentTaskDescriptions.clear();
255-
mListAdapter.notifyDataSetInvalidated();
264+
clearRecentTasksList();
256265
}
257266
}
258267

@@ -374,47 +383,33 @@ protected void onVisibilityChanged(View changedView, int visibility) {
374383
}
375384
}
376385

377-
378-
void applyTaskDescription(ViewHolder h, TaskDescription td, boolean anim) {
379-
h.iconView.setImageDrawable(td.getIcon());
380-
if (h.iconView.getVisibility() != View.VISIBLE) {
381-
if (anim) {
382-
h.iconView.setAnimation(AnimationUtils.loadAnimation(
383-
mContext, R.anim.recent_appear));
384-
}
385-
h.iconView.setVisibility(View.VISIBLE);
386-
}
387-
h.labelView.setText(td.getLabel());
388-
h.thumbnailView.setContentDescription(td.getLabel());
389-
if (h.labelView.getVisibility() != View.VISIBLE) {
390-
if (anim) {
391-
h.labelView.setAnimation(AnimationUtils.loadAnimation(
392-
mContext, R.anim.recent_appear));
393-
}
394-
h.labelView.setVisibility(View.VISIBLE);
395-
}
396-
Bitmap thumbnail = td.getThumbnail();
386+
private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
397387
if (thumbnail != null) {
398388
// Should remove the default image in the frame
399389
// that this now covers, to improve scrolling speed.
400390
// That can't be done until the anim is complete though.
401391
h.thumbnailViewImage.setImageBitmap(thumbnail);
402-
// scale to fill up the full width
403-
Matrix scaleMatrix = new Matrix();
404-
float scale = mThumbnailWidth / (float) thumbnail.getWidth();
405-
scaleMatrix.setScale(scale, scale);
406-
h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
407-
h.thumbnailViewImage.setImageMatrix(scaleMatrix);
408-
if (h.thumbnailViewImage.getVisibility() != View.VISIBLE) {
392+
393+
// scale the image to fill the full width of the ImageView. do this only if
394+
// we haven't set a bitmap before, or if the bitmap size has changed
395+
if (h.thumbnailViewImageBitmap == null ||
396+
h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
397+
h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
398+
Matrix scaleMatrix = new Matrix();
399+
float scale = mThumbnailWidth / (float) thumbnail.getWidth();
400+
scaleMatrix.setScale(scale, scale);
401+
h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
402+
h.thumbnailViewImage.setImageMatrix(scaleMatrix);
403+
}
404+
if (show && h.thumbnailView.getVisibility() != View.VISIBLE) {
409405
if (anim) {
410-
h.thumbnailViewImage.setAnimation(
411-
AnimationUtils.loadAnimation(
412-
mContext, R.anim.recent_appear));
406+
h.thumbnailView.setAnimation(
407+
AnimationUtils.loadAnimation(mContext, R.anim.recent_appear));
413408
}
414-
h.thumbnailViewImage.setVisibility(View.VISIBLE);
409+
h.thumbnailView.setVisibility(View.VISIBLE);
415410
}
411+
h.thumbnailViewImageBitmap = thumbnail;
416412
}
417-
//h.descriptionView.setText(ad.description);
418413
}
419414

420415
void onTaskThumbnailLoaded(TaskDescription ad) {
@@ -432,22 +427,67 @@ void onTaskThumbnailLoaded(TaskDescription ad) {
432427
if (v.getTag() instanceof ViewHolder) {
433428
ViewHolder h = (ViewHolder)v.getTag();
434429
if (h.taskDescription == ad) {
435-
applyTaskDescription(h, ad, true);
430+
// only fade in the thumbnail if recents is already visible-- we
431+
// show it immediately otherwise
432+
boolean animateShow = mShowing &&
433+
mRecentsGlowView.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
434+
updateThumbnail(h, ad.getThumbnail(), true, animateShow);
436435
}
437436
}
438437
}
439438
}
440439
}
441440
}
442441

442+
// additional optimization when we have sofware system buttons - start loading the recent
443+
// tasks on touch down
444+
@Override
445+
public boolean onTouch(View v, MotionEvent ev) {
446+
if (!mShowing) {
447+
int action = ev.getAction() & MotionEvent.ACTION_MASK;
448+
if (action == MotionEvent.ACTION_DOWN) {
449+
// If we set our visibility to INVISIBLE here, we avoid an extra call to onLayout
450+
// later when we become visible
451+
setVisibility(INVISIBLE);
452+
refreshRecentTasksList();
453+
} else if (action == MotionEvent.ACTION_CANCEL) {
454+
setVisibility(GONE);
455+
clearRecentTasksList();
456+
} else if (action == MotionEvent.ACTION_UP) {
457+
if (!v.isPressed()) {
458+
setVisibility(GONE);
459+
clearRecentTasksList();
460+
}
461+
}
462+
}
463+
return false;
464+
}
465+
466+
public void clearRecentTasksList() {
467+
// Clear memory used by screenshots
468+
if (mRecentTaskDescriptions != null) {
469+
mRecentTasksLoader.cancelLoadingThumbnails();
470+
mRecentTaskDescriptions.clear();
471+
mListAdapter.notifyDataSetInvalidated();
472+
mRecentTasksDirty = true;
473+
}
474+
}
475+
476+
public void refreshRecentTasksList() {
477+
refreshRecentTasksList(null);
478+
}
479+
443480
private void refreshRecentTasksList(ArrayList<TaskDescription> recentTasksList) {
444-
if (recentTasksList != null) {
445-
mRecentTaskDescriptions = recentTasksList;
446-
} else {
447-
mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
481+
if (mRecentTasksDirty) {
482+
if (recentTasksList != null) {
483+
mRecentTaskDescriptions = recentTasksList;
484+
} else {
485+
mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
486+
}
487+
mListAdapter.notifyDataSetInvalidated();
488+
updateUiElements(getResources().getConfiguration());
489+
mRecentTasksDirty = false;
448490
}
449-
mListAdapter.notifyDataSetInvalidated();
450-
updateUiElements(getResources().getConfiguration());
451491
}
452492

453493
public ArrayList<TaskDescription> getRecentTasksList() {

packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -435,13 +435,18 @@ public void onClick(View v) {
435435
}
436436
};
437437

438+
private void prepareNavigationBarView() {
439+
mNavigationBarView.reorient();
440+
441+
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
442+
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
443+
}
444+
438445
// For small-screen devices (read: phones) that lack hardware navigation buttons
439446
private void addNavigationBar() {
440447
if (mNavigationBarView == null) return;
441448

442-
mNavigationBarView.reorient();
443-
444-
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
449+
prepareNavigationBarView();
445450

446451
WindowManagerImpl.getDefault().addView(
447452
mNavigationBarView, getNavigationBarLayoutParams());
@@ -450,9 +455,7 @@ private void addNavigationBar() {
450455
private void repositionNavigationBar() {
451456
if (mNavigationBarView == null) return;
452457

453-
mNavigationBarView.reorient();
454-
455-
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
458+
prepareNavigationBarView();
456459

457460
WindowManagerImpl.getDefault().updateViewLayout(
458461
mNavigationBarView, getNavigationBarLayoutParams());
@@ -2007,8 +2010,8 @@ void updateExpandedSize() {
20072010
}
20082011

20092012
public void toggleRecentApps() {
2010-
int msg = (mRecentsPanel.getVisibility() == View.GONE)
2011-
? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
2013+
int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
2014+
? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
20122015
mHandler.removeMessages(msg);
20132016
mHandler.sendEmptyMessage(msg);
20142017
}

packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,7 @@ public boolean onTouch(View v, MotionEvent ev) {
587587

588588
// Add the windows
589589
addPanelWindows();
590+
mRecentButton.setOnTouchListener(mRecentsPanel);
590591

591592
mPile = (ViewGroup)mNotificationPanel.findViewById(R.id.content);
592593
mPile.removeAllViews();
@@ -1805,8 +1806,8 @@ public void clearAll() {
18051806
}
18061807

18071808
public void toggleRecentApps() {
1808-
int msg = (mRecentsPanel.getVisibility() == View.GONE)
1809-
? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
1809+
int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
1810+
? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
18101811
mHandler.removeMessages(msg);
18111812
mHandler.sendEmptyMessage(msg);
18121813
}

0 commit comments

Comments
 (0)