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
This commit is contained in:
@@ -155,6 +155,7 @@
|
||||
<assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
|
||||
<assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
|
||||
<assign-permission name="android.permission.BACKUP" uid="shell" />
|
||||
<assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" />
|
||||
|
||||
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
|
||||
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
|
||||
|
||||
@@ -277,10 +277,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
|
||||
*/
|
||||
public boolean setDrawableByLayerId(int id, Drawable drawable) {
|
||||
final ChildDrawable[] layers = mLayerState.mChildren;
|
||||
drawable.setCallback(this);
|
||||
|
||||
for (int i = mLayerState.mNum - 1; i >= 0; i--) {
|
||||
if (layers[i].mId == id) {
|
||||
if (layers[i].mDrawable != null) {
|
||||
if (drawable != null) {
|
||||
Rect bounds = layers[i].mDrawable.getBounds();
|
||||
drawable.setBounds(bounds);
|
||||
}
|
||||
layers[i].mDrawable.setCallback(null);
|
||||
}
|
||||
if (drawable != null) {
|
||||
drawable.setCallback(this);
|
||||
}
|
||||
layers[i].mDrawable = drawable;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<!-- started from PhoneWindowManager
|
||||
TODO: Should have an android:permission attribute -->
|
||||
<service android:name=".screenshot.TakeScreenshotService"
|
||||
android:process=":screenshot"
|
||||
android:exported="false" />
|
||||
|
||||
<service android:name=".LoadAverageService"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -13,7 +13,8 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:drawable="@drawable/recents_thumbnail_bg" android:id="@+id/base_layer"/>
|
||||
<item android:drawable="@drawable/recents_thumbnail_overlay" android:id="@+id/overlay_layer"/>
|
||||
</layer-list>
|
||||
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
/>
|
||||
@@ -32,8 +32,14 @@
|
||||
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
|
||||
android:scaleType="center"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/recents_thumbnail_layers"
|
||||
/>
|
||||
android:background="@drawable/recents_thumbnail_bg"
|
||||
android:foreground="@drawable/recents_thumbnail_overlay">
|
||||
<ImageView android:id="@+id/app_thumbnail_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView android:id="@+id/app_icon"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -45,6 +51,7 @@
|
||||
android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
|
||||
android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
|
||||
android:adjustViewBounds="true"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
|
||||
<TextView android:id="@+id/app_label"
|
||||
@@ -60,6 +67,7 @@
|
||||
android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
|
||||
<TextView android:id="@+id/app_description"
|
||||
|
||||
@@ -32,8 +32,14 @@
|
||||
android:clickable="true"
|
||||
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
|
||||
android:scaleType="center"
|
||||
android:background="@drawable/recents_thumbnail_layers"
|
||||
/>
|
||||
android:background="@drawable/recents_thumbnail_bg"
|
||||
android:foreground="@drawable/recents_thumbnail_overlay">
|
||||
<ImageView android:id="@+id/app_thumbnail_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView android:id="@+id/app_icon"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -32,8 +32,14 @@
|
||||
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
|
||||
android:scaleType="center"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/recents_thumbnail_layers"
|
||||
/>
|
||||
android:background="@drawable/recents_thumbnail_bg"
|
||||
android:foreground="@drawable/recents_thumbnail_overlay">
|
||||
<ImageView android:id="@+id/app_thumbnail_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView android:id="@+id/app_icon"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
View old = null;
|
||||
if (i < mLinearLayout.getChildCount()) {
|
||||
old = mLinearLayout.getChildAt(i);
|
||||
old.setVisibility(View.VISIBLE);
|
||||
}
|
||||
final View view = mAdapter.getView(i, old, mLinearLayout);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ import java.util.Date;
|
||||
class SaveImageInBackgroundData {
|
||||
Context context;
|
||||
Bitmap image;
|
||||
Runnable finisher;
|
||||
int result;
|
||||
}
|
||||
|
||||
@@ -141,6 +142,7 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi
|
||||
Toast.makeText(params.context, R.string.screenshot_saving_toast,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
params.finisher.run();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -231,11 +233,9 @@ class GlobalScreenshot {
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
|
||||
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM
|
||||
| WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
|
||||
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
mWindowLayoutParams.token = new Binder();
|
||||
mWindowLayoutParams.setTitle("ScreenshotAnimation");
|
||||
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
mDisplay = mWindowManager.getDefaultDisplay();
|
||||
@@ -244,10 +244,11 @@ class GlobalScreenshot {
|
||||
/**
|
||||
* Creates a new worker thread and saves the screenshot to the media store.
|
||||
*/
|
||||
private void saveScreenshotInWorkerThread() {
|
||||
private void saveScreenshotInWorkerThread(Runnable finisher) {
|
||||
SaveImageInBackgroundData data = new SaveImageInBackgroundData();
|
||||
data.context = mContext;
|
||||
data.image = mScreenBitmap;
|
||||
data.finisher = finisher;
|
||||
new SaveImageInBackgroundTask().execute(data);
|
||||
}
|
||||
|
||||
@@ -269,7 +270,7 @@ class GlobalScreenshot {
|
||||
/**
|
||||
* Takes a screenshot of the current display and shows an animation.
|
||||
*/
|
||||
void takeScreenshot() {
|
||||
void takeScreenshot(Runnable finisher) {
|
||||
// We need to orient the screenshot correctly (and the Surface api seems to take screenshots
|
||||
// only in the natural orientation of the device :!)
|
||||
mDisplay.getRealMetrics(mDisplayMetrics);
|
||||
@@ -302,18 +303,19 @@ class GlobalScreenshot {
|
||||
if (mScreenBitmap == null) {
|
||||
Toast.makeText(mContext, R.string.screenshot_failed_toast,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
finisher.run();
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the post-screenshot animation
|
||||
startAnimation();
|
||||
startAnimation(finisher);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts the animation after taking the screenshot
|
||||
*/
|
||||
private void startAnimation() {
|
||||
private void startAnimation(final Runnable finisher) {
|
||||
// Add the view for the animation
|
||||
mScreenshotView.setImageBitmap(mScreenBitmap);
|
||||
mScreenshotLayout.requestFocus();
|
||||
@@ -332,8 +334,7 @@ class GlobalScreenshot {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// Save the screenshot once we have a bit of time now
|
||||
saveScreenshotInWorkerThread();
|
||||
|
||||
saveScreenshotInWorkerThread(finisher);
|
||||
mWindowManager.removeView(mScreenshotLayout);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,7 +26,11 @@ import android.net.Uri;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.app.AlertActivity;
|
||||
@@ -39,12 +43,30 @@ public class TakeScreenshotService extends Service {
|
||||
|
||||
private static GlobalScreenshot mScreenshot;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case 1:
|
||||
final Messenger callback = msg.replyTo;
|
||||
if (mScreenshot == null) {
|
||||
mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
|
||||
}
|
||||
mScreenshot.takeScreenshot(new Runnable() {
|
||||
@Override public void run() {
|
||||
Message reply = Message.obtain(null, 1);
|
||||
try {
|
||||
callback.send(reply);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (mScreenshot == null) {
|
||||
mScreenshot = new GlobalScreenshot(this);
|
||||
}
|
||||
mScreenshot.takeScreenshot();
|
||||
return null;
|
||||
return new Messenger(mHandler).getBinder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.Dialog;
|
||||
import android.app.Notification;
|
||||
@@ -371,9 +372,11 @@ public class PhoneStatusBar extends StatusBar {
|
||||
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
|
||||
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
|
||||
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
|
||||
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
|
||||
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
|
||||
(translucent ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
|
||||
if (ActivityManager.isHighEndGfx(mDisplay)) {
|
||||
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
|
||||
}
|
||||
lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
|
||||
lp.setTitle("RecentsPanel");
|
||||
lp.windowAnimations = R.style.Animation_RecentPanel;
|
||||
|
||||
@@ -41,6 +41,8 @@ import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.LocalPowerManager;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -2396,22 +2398,67 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConnection mScreenshotConnection = null;
|
||||
Runnable mScreenshotTimeout = null;
|
||||
|
||||
void finishScreenshot(ServiceConnection conn) {
|
||||
if (mScreenshotConnection == conn) {
|
||||
mContext.unbindService(conn);
|
||||
mScreenshotConnection = null;
|
||||
if (mScreenshotTimeout != null) {
|
||||
mHandler.removeCallbacks(mScreenshotTimeout);
|
||||
mScreenshotTimeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void takeScreenshot() {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mScreenshotConnection != null) {
|
||||
return;
|
||||
}
|
||||
ComponentName cn = new ComponentName("com.android.systemui",
|
||||
"com.android.systemui.screenshot.TakeScreenshotService");
|
||||
Intent intent = new Intent();
|
||||
intent.setComponent(cn);
|
||||
ServiceConnection conn = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {}
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
if (mScreenshotConnection != this) {
|
||||
return;
|
||||
}
|
||||
Messenger messenger = new Messenger(service);
|
||||
Message msg = Message.obtain(null, 1);
|
||||
final ServiceConnection myConn = this;
|
||||
Handler h = new Handler(mHandler.getLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
finishScreenshot(myConn);
|
||||
}
|
||||
};
|
||||
msg.replyTo = new Messenger(h);
|
||||
try {
|
||||
messenger.send(msg);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {}
|
||||
};
|
||||
mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
|
||||
mContext.unbindService(conn);
|
||||
if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
|
||||
mScreenshotConnection = conn;
|
||||
mScreenshotTimeout = new Runnable() {
|
||||
@Override public void run() {
|
||||
if (mScreenshotConnection != null) {
|
||||
finishScreenshot(mScreenshotConnection);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
mHandler.postDelayed(mScreenshotTimeout, 10000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user