diff options
13 files changed, 340 insertions, 85 deletions
diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 05bd626..0353a47 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -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" /> diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 49dbbca..6698d31 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -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; } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 2080fad..d10911f 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -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" diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml b/packages/SystemUI/res/anim/recent_appear.xml index 6cae2c4..4400d9d 100644 --- a/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml +++ b/packages/SystemUI/res/anim/recent_appear.xml @@ -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>
\ No newline at end of file + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:fromAlpha="0.0" android:toAlpha="1.0" + android:duration="@android:integer/config_shortAnimTime" + /> diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml index 8c29042..16008a3 100644 --- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml @@ -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" diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml index c705a69..c0fce71 100644 --- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml @@ -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" diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml index 386ce30..5306508 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml @@ -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" 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; } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 86dc9a6..fe255cb 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -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); } }); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java index 35eaedf..05ff8be 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java @@ -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(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 2e14bef..e894831 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -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; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index b60a038..7764e35 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -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); + } } }); } |