diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-08-17 16:20:47 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-08-17 17:45:05 -0700 |
commit | fc8fa638617efb5695a1f89ea75375faebbe2a40 (patch) | |
tree | 685aeed4995ea17399accf5d46545038235d5105 /packages/SystemUI/src/com/android/systemui/recent | |
parent | 9a5505f0253a9114aea6192a22da6ec1c1b85ed2 (diff) | |
download | frameworks_base-fc8fa638617efb5695a1f89ea75375faebbe2a40.zip frameworks_base-fc8fa638617efb5695a1f89ea75375faebbe2a40.tar.gz frameworks_base-fc8fa638617efb5695a1f89ea75375faebbe2a40.tar.bz2 |
Fix issue #5128639: SystemUI grows by 10MB after taking a screenshot
We now do the screenshot in a separate process.
Also change the recents panel to not use hardware acceleration
on lower-end devices. And improve how it gets shown to not
load all data up-front which results in a long delay when you have
lots of recents.
Change-Id: Ia309a90f9939e5405758621b3f7114597bd0c02a
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/recent')
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java | 217 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java | 43 |
2 files changed, 205 insertions, 55 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java index 28a5cc8..8c03ef8 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java @@ -41,6 +41,10 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.net.Uri; +import android.os.AsyncTask; +import android.os.Handler; +import android.os.Process; +import android.os.SystemClock; import android.provider.Settings; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -51,12 +55,15 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.animation.AnimationUtils; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; +import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.RelativeLayout; +import android.widget.ScrollView; import android.widget.TextView; import com.android.systemui.R; @@ -68,11 +75,12 @@ import com.android.systemui.statusbar.tablet.TabletStatusBar; public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener { static final String TAG = "RecentsListView"; - static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG; + static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false; private static final int DISPLAY_TASKS = 20; private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps private StatusBar mBar; private ArrayList<ActivityDescription> mActivityDescriptions; + private AsyncTask<Void, Integer, Void> mThumbnailLoader; private int mIconDpi; private View mRecentsScrim; private View mRecentsGlowView; @@ -87,31 +95,47 @@ public class RecentsPanelView extends RelativeLayout private Choreographer mChoreo; private View mRecentsDismissButton; private ActivityDescriptionAdapter mListAdapter; + private final Handler mHandler = new Handler(); - /* package */ final static class ActivityDescription { + /* package */ final class ActivityDescription { + final ActivityManager.RecentTaskInfo recentTaskInfo; + final ResolveInfo resolveInfo; int taskId; // application task id for curating apps - Bitmap thumbnail; // generated by Activity.onCreateThumbnail() - Drawable icon; // application package icon - String label; // application package label - CharSequence description; // generated by Activity.onCreateDescription() Intent intent; // launch intent for application Matrix matrix; // arbitrary rotation matrix to correct orientation String packageName; // used to override animations (see onClick()) int position; // position in list - public ActivityDescription(Bitmap _thumbnail, - Drawable _icon, String _label, CharSequence _desc, Intent _intent, - int _id, int _pos, String _packageName) - { - thumbnail = _thumbnail; - icon = _icon; - label = _label; - description = _desc; + private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail() + private Drawable mIcon; // application package icon + private CharSequence mLabel; // application package label + + public ActivityDescription(ActivityManager.RecentTaskInfo _recentInfo, + ResolveInfo _resolveInfo, Intent _intent, + int _id, int _pos, String _packageName) { + recentTaskInfo = _recentInfo; + resolveInfo = _resolveInfo; intent = _intent; taskId = _id; position = _pos; packageName = _packageName; } + + public CharSequence getLabel() { + return mLabel; + } + + public Drawable getIcon() { + return mIcon; + } + + public void setThumbnail(Bitmap thumbnail) { + mThumbnail = compositeBitmap(mGlowBitmap, thumbnail); + } + + public Bitmap getThumbnail() { + return mThumbnail; + } } private final class OnLongClickDelegate implements View.OnLongClickListener { @@ -126,6 +150,7 @@ public class RecentsPanelView extends RelativeLayout /* package */ final static class ViewHolder { View thumbnailView; + ImageView thumbnailViewImage; ImageView iconView; TextView labelView; TextView descriptionView; @@ -157,6 +182,8 @@ public class RecentsPanelView extends RelativeLayout convertView = mInflater.inflate(R.layout.status_bar_recent_item, null); holder = new ViewHolder(); holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail); + holder.thumbnailViewImage = (ImageView) convertView.findViewById( + R.id.app_thumbnail_image); 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); @@ -169,11 +196,10 @@ public class RecentsPanelView extends RelativeLayout final int activityId = mActivityDescriptions.size() - position - 1; final ActivityDescription activityDescription = mActivityDescriptions.get(activityId); - final Bitmap thumb = activityDescription.thumbnail; - updateDrawable(holder.thumbnailView, compositeBitmap(mGlowBitmap, thumb)); - holder.iconView.setImageDrawable(activityDescription.icon); - holder.labelView.setText(activityDescription.label); - holder.descriptionView.setText(activityDescription.description); + holder.thumbnailViewImage.setImageBitmap(activityDescription.getThumbnail()); + holder.iconView.setImageDrawable(activityDescription.getIcon()); + holder.labelView.setText(activityDescription.getLabel()); + holder.descriptionView.setText(activityDescription.recentTaskInfo.description); holder.thumbnailView.setTag(activityDescription); holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView)); holder.activityDescription = activityDescription; @@ -201,20 +227,6 @@ public class RecentsPanelView extends RelativeLayout return x >= l && x < r && y >= t && y < b; } - private void updateDrawable(View thumbnailView, Bitmap bitmap) { - Drawable d = thumbnailView.getBackground(); - if (d instanceof LayerDrawable) { - LayerDrawable layerD = (LayerDrawable) d; - Drawable thumb = layerD.findDrawableByLayerId(R.id.base_layer); - if (thumb != null) { - layerD.setDrawableByLayerId(R.id.base_layer, - new BitmapDrawable(getResources(), bitmap)); - return; - } - } - Log.w(TAG, "Failed to update drawable"); - } - public void show(boolean show, boolean animate) { if (animate) { if (mShowing != show) { @@ -373,12 +385,12 @@ public class RecentsPanelView extends RelativeLayout } } - private Drawable getFullResDefaultActivityIcon() { + Drawable getFullResDefaultActivityIcon() { return getFullResIcon(Resources.getSystem(), com.android.internal.R.mipmap.sym_def_app_icon); } - private Drawable getFullResIcon(Resources resources, int iconId) { + Drawable getFullResIcon(Resources resources, int iconId) { try { return resources.getDrawableForDensity(iconId, mIconDpi); } catch (Resources.NotFoundException e) { @@ -442,15 +454,13 @@ public class RecentsPanelView extends RelativeLayout final String title = info.loadLabel(pm).toString(); // Drawable icon = info.loadIcon(pm); Drawable icon = getFullResIcon(resolveInfo, pm); - int id = recentTasks.get(i).id; + int id = recentInfo.id; if (title != null && title.length() > 0 && icon != null) { if (DEBUG) Log.v(TAG, "creating activity desc for id=" + id + ", label=" + title); ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails( recentInfo.persistentId); - ActivityDescription item = new ActivityDescription( - thumbs != null ? thumbs.mainThumbnail : null, - icon, title, recentInfo.description, intent, id, - index, info.packageName); + ActivityDescription item = new ActivityDescription(recentInfo, + resolveInfo, intent, id, index, info.packageName); activityDescriptions.add(item); ++index; } else { @@ -474,12 +484,137 @@ public class RecentsPanelView extends RelativeLayout return desc; } + void loadActivityDescription(ActivityDescription ad, int index) { + final ActivityManager am = (ActivityManager) + mContext.getSystemService(Context.ACTIVITY_SERVICE); + final PackageManager pm = mContext.getPackageManager(); + ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails( + ad.recentTaskInfo.persistentId); + CharSequence label = ad.resolveInfo.activityInfo.loadLabel(pm); + Drawable icon = getFullResIcon(ad.resolveInfo, pm); + if (DEBUG) Log.v(TAG, "Loaded bitmap for #" + index + " in " + + ad + ": " + thumbs.mainThumbnail); + synchronized (ad) { + ad.mLabel = label; + ad.mIcon = icon; + ad.setThumbnail(thumbs.mainThumbnail); + } + } + + void applyActivityDescription(ActivityDescription ad, int index, boolean anim) { + synchronized (ad) { + if (mRecentsContainer != null) { + ViewGroup container = mRecentsContainer; + if (container instanceof HorizontalScrollView + || container instanceof ScrollView) { + 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++) { + View v = container.getChildAt(i); + if (v.getTag() instanceof ViewHolder) { + ViewHolder h = (ViewHolder)v.getTag(); + if (h.activityDescription == ad) { + if (DEBUG) Log.v(TAG, "Updatating thumbnail #" + index + " in " + + h.activityDescription + + ": " + ad.getThumbnail()); + h.iconView.setImageDrawable(ad.getIcon()); + if (anim) { + h.iconView.setAnimation(AnimationUtils.loadAnimation( + mContext, R.anim.recent_appear)); + } + h.iconView.setVisibility(View.VISIBLE); + h.labelView.setText(ad.getLabel()); + if (anim) { + h.labelView.setAnimation(AnimationUtils.loadAnimation( + mContext, R.anim.recent_appear)); + } + h.labelView.setVisibility(View.VISIBLE); + Bitmap thumbnail = ad.getThumbnail(); + if (thumbnail != null) { + // Should remove the default image in the frame + // that this now covers, to improve scrolling speed. + // That can't be done until the anim is complete though. + h.thumbnailViewImage.setImageBitmap(thumbnail); + if (anim) { + h.thumbnailViewImage.setAnimation(AnimationUtils.loadAnimation( + mContext, R.anim.recent_appear)); + } + h.thumbnailViewImage.setVisibility(View.VISIBLE); + } + } + } + } + } + } + } + private void refreshApplicationList() { + if (mThumbnailLoader != null) { + mThumbnailLoader.cancel(false); + mThumbnailLoader = null; + } mActivityDescriptions = getRecentTasks(); mListAdapter.notifyDataSetInvalidated(); if (mActivityDescriptions.size() > 0) { if (DEBUG) Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps"); updateUiElements(getResources().getConfiguration()); + final ArrayList<ActivityDescription> descriptions = mActivityDescriptions; + loadActivityDescription(descriptions.get(0), 0); + applyActivityDescription(descriptions.get(0), 0, false); + if (descriptions.size() > 1) { + mThumbnailLoader = new AsyncTask<Void, Integer, Void>() { + @Override + protected void onProgressUpdate(Integer... values) { + final ActivityDescription ad = descriptions.get(values[0]); + if (!isCancelled()) { + applyActivityDescription(ad, values[0], true); + } + // This is to prevent the loader thread from getting ahead + // of our UI updates. + mHandler.post(new Runnable() { + @Override public void run() { + synchronized (ad) { + ad.notifyAll(); + } + } + }); + } + + @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++) { + ActivityDescription ad = descriptions.get(i); + loadActivityDescription(ad, i); + long now = SystemClock.uptimeMillis(); + nextTime += 200; + if (nextTime > now) { + try { + Thread.sleep(nextTime-now); + } catch (InterruptedException e) { + } + } + if (isCancelled()) { + break; + } + synchronized (ad) { + publishProgress(i); + try { + ad.wait(500); + } catch (InterruptedException e) { + } + } + } + Process.setThreadPriority(origPri); + return null; + } + }; + mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } } else { // Immediately hide this panel if (DEBUG) Log.v(TAG, "Nothing to show"); @@ -548,7 +683,7 @@ public class RecentsPanelView extends RelativeLayout public void handleSwipe(View view) { ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription; - if (DEBUG) Log.v(TAG, "Jettison " + ad.label); + if (DEBUG) Log.v(TAG, "Jettison " + ad.getLabel()); mActivityDescriptions.remove(ad); // Handled by widget containers to enable LayoutTransitions properly diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java index 89900a1..959328f 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java @@ -66,20 +66,34 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper private void update() { 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++) { - final View view = mAdapter.getView(i, null, mLinearLayout); - view.setClickable(true); - view.setOnLongClickListener(mOnLongClick); - - final View thumbnail = getChildContentView(view); - // thumbnail is set to clickable in the layout file - thumbnail.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.handleOnClick(view); - } - }); + View old = null; + if (i < mLinearLayout.getChildCount()) { + old = mLinearLayout.getChildAt(i); + old.setVisibility(View.VISIBLE); + } + final View view = mAdapter.getView(i, old, mLinearLayout); + + if (old == null) { + view.setClickable(true); + view.setOnLongClickListener(mOnLongClick); - mLinearLayout.addView(view); + final View thumbnail = getChildContentView(view); + // thumbnail is set to clickable in the layout file + thumbnail.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mCallback.handleOnClick(view); + } + }); + + mLinearLayout.addView(view); + } + } + for (int i = mAdapter.getCount(); i < mLinearLayout.getChildCount(); i++) { + mLinearLayout.getChildAt(i).setVisibility(View.GONE); } // Scroll to end after layout. post(new Runnable() { @@ -128,8 +142,9 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper final float y = ev.getY() + getScrollY(); for (int i = 0; i < mLinearLayout.getChildCount(); i++) { View item = mLinearLayout.getChildAt(i); - if (x >= item.getLeft() && x < item.getRight() - && y >= item.getTop() && y < item.getBottom()) { + if (item.getVisibility() == View.VISIBLE + && x >= item.getLeft() && x < item.getRight() + && y >= item.getTop() && y < item.getBottom()) { return item; } } |