import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskViewTransform;
+import java.lang.ref.WeakReference;
+
/* Service */
public class RecentsService extends Service {
// XXX: This should be getting the message from recents definition
final static int MSG_UPDATE_RECENTS_FOR_CONFIGURATION = 0;
- class MessageHandler extends Handler {
+ /** This Handler should be static to prevent holding onto a reference to the service. */
+ static class MessageHandler extends Handler {
+ WeakReference<Context> mContext;
+
+ MessageHandler(Context context) {
+ // Keep a weak ref to the context instead of a strong ref
+ mContext = new WeakReference<Context>(context);
+ }
+
@Override
public void handleMessage(Message msg) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|handleMessage]", msg);
+ Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ "[RecentsService|handleMessage]", msg);
if (msg.what == MSG_UPDATE_RECENTS_FOR_CONFIGURATION) {
- Context context = RecentsService.this;
+ Context context = mContext.get();
+ if (context == null) return;
+
RecentsTaskLoader.initialize(context);
RecentsConfiguration.reinitialize(context);
}
}
- Messenger mMessenger = new Messenger(new MessageHandler());
+ Messenger mMessenger = new Messenger(new MessageHandler(this));
@Override
public void onCreate() {
PackageManager.GET_META_DATA);
Drawable icon = info.loadIcon(pm);
if (!mCancelled) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [TaskResourceLoader|loadIcon]",
- icon);
- loadIcon = icon;
- mIconCache.put(t.key, icon);
+ if (icon != null) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [TaskResourceLoader|loadIcon]",
+ icon);
+ loadIcon = icon;
+ mIconCache.put(t.key, icon);
+ }
}
}
// Load the thumbnail
}
if (task.icon == null) {
task.icon = info.loadIcon(pm);
- mIconCache.put(task.key, task.icon);
+ if (task.icon != null) {
+ mIconCache.put(task.key, task.icon);
+ } else {
+ task.icon = mDefaultIcon;
+ }
}
// Load the thumbnail (if possible and not the foremost task, from the cache)
Console.log(Constants.DebugFlags.App.TaskDataLoader,
"[RecentsTaskLoader|loadingTaskThumbnail]");
task.thumbnail = am.getTaskTopThumbnail(t.id);
- mThumbnailCache.put(task.key, task.thumbnail);
+ if (task.thumbnail != null) {
+ mThumbnailCache.put(task.key, task.thumbnail);
+ } else {
+ task.thumbnail = mDefaultThumbnail;
+ }
}
// Create as many tasks a we want to multiply by
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]", "width: " + width + " height: " + height, Console.AnsiGreen);
+ Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]",
+ "width: " + width + " height: " + height, Console.AnsiGreen);
// We measure our stack views sans the status bar. It will handle the nav bar itself.
RecentsConfiguration config = RecentsConfiguration.getInstance();
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]", new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
+ Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]",
+ new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
// We offset our stack views by the status bar height. It will handle the nav bar itself.
RecentsConfiguration config = RecentsConfiguration.getInstance();
top += config.systemInsets.top;
int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll, curScroll));
if (newScroll != curScroll) {
// Enable hw layers on the stack
- addHwLayersRefCount();
+ addHwLayersRefCount("animateBoundScroll");
// Abort any current animations
- mScroller.abortAnimation();
+ abortScroller();
if (mScrollAnimator != null) {
mScrollAnimator.cancel();
mScrollAnimator.removeAllListeners();
@Override
public void onAnimationEnd(Animator animation) {
// Disable hw layers on the stack
- decHwLayersRefCount();
+ decHwLayersRefCount("animateBoundScroll");
}
});
mScrollAnimator.start();
}
}
+ void abortScroller() {
+ if (!mScroller.isFinished()) {
+ // Abort the scroller
+ mScroller.abortAnimation();
+ // And disable hw layers on the stack
+ decHwLayersRefCount("flingScroll");
+ }
+ }
+
/** Bounds the current scroll if necessary */
public boolean boundScroll() {
int curScroll = getStackScroll();
}
/** Enables the hw layers and increments the hw layer requirement ref count */
- void addHwLayersRefCount() {
+ void addHwLayersRefCount(String reason) {
Console.log(Constants.DebugFlags.UI.HwLayers,
"[TaskStackView|addHwLayersRefCount] refCount: " +
- mHwLayersRefCount + "->" + (mHwLayersRefCount + 1));
+ mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
if (mHwLayersRefCount == 0) {
// Enable hw layers on each of the children
int childCount = getChildCount();
/** Decrements the hw layer requirement ref count and disables the hw layers when we don't
need them anymore. */
- void decHwLayersRefCount() {
+ void decHwLayersRefCount(String reason) {
Console.log(Constants.DebugFlags.UI.HwLayers,
"[TaskStackView|decHwLayersRefCount] refCount: " +
- mHwLayersRefCount + "->" + (mHwLayersRefCount - 1));
+ mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
mHwLayersRefCount--;
if (mHwLayersRefCount == 0) {
// Disable hw layers on each of the children
// If we just finished scrolling, then disable the hw layers
if (mScroller.isFinished()) {
- decHwLayersRefCount();
+ decHwLayersRefCount("finishedFlingScroll");
}
}
}
mActivePointerId = ev.getPointerId(0);
mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY);
// Stop the current scroll if it is still flinging
- mSv.mScroller.abortAnimation();
+ mSv.abortScroller();
mSv.abortBoundScrollAnimation();
// Initialize the velocity tracker
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
// Check if the scroller is finished yet
mIsScrolling = !mSv.mScroller.isFinished();
- // Enable HW layers
- mSv.addHwLayersRefCount();
break;
}
case MotionEvent.ACTION_MOVE: {
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
+ // Enable HW layers
+ mSv.addHwLayersRefCount("stackScroll");
}
mLastMotionX = x;
case MotionEvent.ACTION_UP: {
// Animate the scroll back if we've cancelled
mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
+ // Disable HW layers
+ if (mIsScrolling) {
+ mSv.decHwLayersRefCount("stackScroll");
+ }
// Reset the drag state and the velocity tracker
mIsScrolling = false;
mActivePointerId = INACTIVE_POINTER_ID;
mActiveTaskView = null;
mTotalScrollMotion = 0;
recycleVelocityTracker();
- // Disable HW layers
- mSv.decHwLayersRefCount();
break;
}
}
mActivePointerId = ev.getPointerId(0);
mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY);
// Stop the current scroll if it is still flinging
- mSv.mScroller.abortAnimation();
+ mSv.abortScroller();
mSv.abortBoundScrollAnimation();
// Initialize the velocity tracker
initOrResetVelocityTracker();
parent.requestDisallowInterceptTouchEvent(true);
}
// Enable HW layers
- mSv.addHwLayersRefCount();
+ mSv.addHwLayersRefCount("stackScroll");
}
}
if (mIsScrolling) {
"scroll: " + mSv.getStackScroll() + " velocity: " + velocity,
Console.AnsiGreen);
// Enable HW layers on the stack
- mSv.addHwLayersRefCount();
+ mSv.addHwLayersRefCount("flingScroll");
// Fling scroll
mSv.mScroller.fling(0, mSv.getStackScroll(),
0, -velocity,
mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
}
+ if (mIsScrolling) {
+ // Disable HW layers
+ mSv.decHwLayersRefCount("stackScroll");
+ }
mActivePointerId = INACTIVE_POINTER_ID;
mIsScrolling = false;
mTotalScrollMotion = 0;
recycleVelocityTracker();
- // Disable HW layers
- mSv.decHwLayersRefCount();
break;
}
case MotionEvent.ACTION_CANCEL: {
+ if (mIsScrolling) {
+ // Disable HW layers
+ mSv.decHwLayersRefCount("stackScroll");
+ }
if (mSv.isScrollOutOfBounds()) {
// Animate the scroll back into bounds
// XXX: Make this animation a function of the velocity OR distance
mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
}
-
mActivePointerId = INACTIVE_POINTER_ID;
mIsScrolling = false;
mTotalScrollMotion = 0;
recycleVelocityTracker();
- // Disable HW layers
- mSv.decHwLayersRefCount();
break;
}
}
@Override
public void onBeginDrag(View v) {
// Enable HW layers
- mSv.addHwLayersRefCount();
+ mSv.addHwLayersRefCount("swipeBegin");
// Disallow parents from intercepting touch events
final ViewParent parent = mSv.getParent();
if (parent != null) {
}
// Disable HW layers
- mSv.decHwLayersRefCount();
+ mSv.decHwLayersRefCount("swipeComplete");
}
@Override
@Override
public void onDragCancelled(View v) {
// Disable HW layers
- mSv.decHwLayersRefCount();
+ mSv.decHwLayersRefCount("swipeCancelled");
}
}