summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src/com/android/systemui/recent
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-08-17 16:20:47 -0700
committerDianne Hackborn <hackbod@google.com>2011-08-17 17:45:05 -0700
commitfc8fa638617efb5695a1f89ea75375faebbe2a40 (patch)
tree685aeed4995ea17399accf5d46545038235d5105 /packages/SystemUI/src/com/android/systemui/recent
parent9a5505f0253a9114aea6192a22da6ec1c1b85ed2 (diff)
downloadframeworks_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.java217
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java43
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;
}
}