3737import android .view .MenuItem ;
3838import android .view .MotionEvent ;
3939import android .view .View ;
40+ import android .view .ViewConfiguration ;
4041import android .view .ViewGroup ;
4142import android .view .accessibility .AccessibilityEvent ;
4243import android .view .animation .AnimationUtils ;
5758import com .android .systemui .statusbar .tablet .StatusBarPanel ;
5859import 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 () {
0 commit comments