diff options
9 files changed, 217 insertions, 51 deletions
diff --git a/packages/SystemUI/res/drawable/recents_task_view_header_bg_color.xml b/packages/SystemUI/res/drawable/recents_task_view_header_bg_color.xml new file mode 100644 index 0000000..5f9341c --- /dev/null +++ b/packages/SystemUI/res/drawable/recents_task_view_header_bg_color.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 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. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:topLeftRadius="@dimen/recents_task_view_rounded_corners_radius" + android:topRightRadius="@dimen/recents_task_view_rounded_corners_radius"/> + <solid android:color="#00000000" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml index 4cb8498..1b982fb 100644 --- a/packages/SystemUI/res/layout/recents_task_view.xml +++ b/packages/SystemUI/res/layout/recents_task_view.xml @@ -15,10 +15,9 @@ --> <com.android.systemui.recents.views.TaskView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" + android:layout_width="match_parent" android:layout_height="match_parent" - android:focusable="true" - android:background="#FFffffff"> + android:focusable="true"> <com.android.systemui.recents.views.TaskViewThumbnail android:id="@+id/task_view_thumbnail" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 9654da9..ffe52e2 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -29,6 +29,10 @@ ImageView --> <bool name="config_recents_thumbnail_image_fits_to_xy">false</bool> + <!-- Whether recents should use hardware layers for its taskviews. This flag can be enabled + for devices where the java drawing of round rects may be slow --> + <bool name="config_recents_use_hardware_layers">false</bool> + <!-- The number of app thumbnails we keep in memory --> <integer name="config_recents_max_thumbnail_count">10</integer> diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 2a2caa0..2f5b07b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -119,6 +119,7 @@ public class RecentsConfiguration { public int launchedToTaskId; /** Misc **/ + public boolean useHardwareLayers; public int altTabKeyDelay; /** Dev options and global settings */ @@ -271,6 +272,7 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration); // Misc + useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers); altTabKeyDelay = res.getInteger(R.integer.recents_alt_tab_key_delay); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index e5c06fd..d4b403d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -204,7 +204,8 @@ class TaskResourceLoader implements Runnable { if (!mCancelled) { // Notify that the task data has changed final Drawable newIcon = cachedIcon; - final Bitmap newThumbnail = cachedThumbnail; + final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail + ? null : cachedThumbnail; mMainThreadHandler.post(new Runnable() { @Override public void run() { @@ -252,7 +253,6 @@ public class RecentsTaskLoader { BitmapDrawable mDefaultApplicationIcon; Bitmap mDefaultThumbnail; - Bitmap mLoadingThumbnail; /** Private Constructor */ private RecentsTaskLoader(Context context) { @@ -271,9 +271,6 @@ public class RecentsTaskLoader { mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); mDefaultThumbnail.setHasAlpha(false); mDefaultThumbnail.eraseColor(0xFFffffff); - mLoadingThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); - mLoadingThumbnail.setHasAlpha(false); - mLoadingThumbnail.eraseColor(0xFFffffff); mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon); // Initialize the proxy, cache and loaders @@ -500,17 +497,16 @@ public class RecentsTaskLoader { // use the default assets in their place until they load boolean requiresLoad = (applicationIcon == null) || (thumbnail == null); applicationIcon = applicationIcon != null ? applicationIcon : mDefaultApplicationIcon; - thumbnail = thumbnail != null ? thumbnail : mDefaultThumbnail; if (requiresLoad) { mLoadQueue.addTask(t); } - t.notifyTaskDataLoaded(thumbnail, applicationIcon); + t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, applicationIcon); } /** Releases the task resource data back into the pool. */ public void unloadTaskData(Task t) { mLoadQueue.removeTask(t); - t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon); + t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon); } /** Completely removes the resource data from the pool. */ @@ -519,7 +515,7 @@ public class RecentsTaskLoader { mThumbnailCache.remove(t.key); mApplicationIconCache.remove(t.key); if (notifyTaskDataUnloaded) { - t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon); + t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java index d6889d0..0adc73c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java @@ -44,7 +44,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider { mConfig = RecentsConfiguration.getInstance(); mSourceView = source; mCornerRadius = cornerRadius; - mSourceView.setClipToOutline(true); setClipTop(getClipTop()); setClipRight(getClipRight()); setClipBottom(getClipBottom()); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 51adc28..a1ddf0f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -637,17 +637,31 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Returns the current dim. */ public void setDim(int dim) { mDim = dim; - // Defer setting hardware layers if we have not yet measured, or there is no dim to draw - if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) { - if (mDimAnimator != null) { - mDimAnimator.removeAllListeners(); - mDimAnimator.cancel(); - } + if (mDimAnimator != null) { + mDimAnimator.removeAllListeners(); + mDimAnimator.cancel(); + } + if (mConfig.useHardwareLayers) { + // Defer setting hardware layers if we have not yet measured, or there is no dim to draw + if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) { + if (mDimAnimator != null) { + mDimAnimator.removeAllListeners(); + mDimAnimator.cancel(); + } - int inverse = 255 - mDim; - mDimColorFilter.setColor(Color.argb(0xFF, inverse, inverse, inverse)); - mLayerPaint.setColorFilter(mDimColorFilter); - setLayerType(LAYER_TYPE_HARDWARE, mLayerPaint); + int inverse = 255 - mDim; + mDimColorFilter.setColor(Color.argb(0xFF, inverse, inverse, inverse)); + mLayerPaint.setColorFilter(mDimColorFilter); + setLayerType(LAYER_TYPE_HARDWARE, mLayerPaint); + } + } else { + float dimAlpha = mDim / 255.0f; + if (mThumbnailView != null) { + mThumbnailView.setDimAlpha(dimAlpha); + } + if (mHeaderView != null) { + mHeaderView.setDimAlpha(dim); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index 1743433..fd39126 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -30,10 +30,13 @@ import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.RippleDrawable; +import android.graphics.drawable.ShapeDrawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -58,17 +61,20 @@ public class TaskViewHeader extends FrameLayout { TextView mActivityDescription; RippleDrawable mBackground; - ColorDrawable mBackgroundColor; + GradientDrawable mBackgroundColorDrawable; + int mBackgroundColor; Drawable mLightDismissDrawable; Drawable mDarkDismissDrawable; AnimatorSet mFocusAnimator; ValueAnimator backgroundColorAnimator; + PorterDuffColorFilter mDimFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); boolean mIsFullscreen; boolean mCurrentPrimaryColorIsDark; int mCurrentPrimaryColor; static Paint sHighlightPaint; + private Paint mDimPaint = new Paint(); public TaskViewHeader(Context context) { this(context, null); @@ -140,13 +146,14 @@ public class TaskViewHeader extends FrameLayout { } } - mBackgroundColor = new ColorDrawable(0); + mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable(R.drawable + .recents_task_view_header_bg_color); // Copy the ripple drawable since we are going to be manipulating it mBackground = (RippleDrawable) getContext().getDrawable(R.drawable.recents_task_view_header_bg); mBackground = (RippleDrawable) mBackground.mutate().getConstantState().newDrawable(); mBackground.setColor(ColorStateList.valueOf(0)); - mBackground.setDrawableByLayerId(mBackground.getId(0), mBackgroundColor); + mBackground.setDrawableByLayerId(mBackground.getId(0), mBackgroundColorDrawable); setBackground(mBackground); } @@ -197,7 +204,8 @@ public class TaskViewHeader extends FrameLayout { int existingBgColor = (getBackground() instanceof ColorDrawable) ? ((ColorDrawable) getBackground()).getColor() : 0; if (existingBgColor != t.colorPrimary) { - mBackgroundColor.setColor(t.colorPrimary); + mBackgroundColorDrawable.setColor(t.colorPrimary); + mBackgroundColor = t.colorPrimary; } mCurrentPrimaryColor = t.colorPrimary; mCurrentPrimaryColorIsDark = t.useLightOnPrimaryColor; @@ -276,7 +284,7 @@ public class TaskViewHeader extends FrameLayout { mBackground.setColor(new ColorStateList(states, colors)); mBackground.setState(newStates); // Pulse the background color - int currentColor = mBackgroundColor.getColor(); + int currentColor = mBackgroundColor; int lightPrimaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark); ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(), lightPrimaryColor, currentColor); @@ -289,7 +297,9 @@ public class TaskViewHeader extends FrameLayout { backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - mBackgroundColor.setColor((Integer) animation.getAnimatedValue()); + int color = (int) animation.getAnimatedValue(); + mBackgroundColorDrawable.setColor(color); + mBackgroundColor = color; } }); backgroundColor.setRepeatCount(ValueAnimator.INFINITE); @@ -307,13 +317,15 @@ public class TaskViewHeader extends FrameLayout { } else { if (isRunning) { // Restore the background color - int currentColor = mBackgroundColor.getColor(); + int currentColor = mBackgroundColor; ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(), currentColor, mCurrentPrimaryColor); backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - mBackgroundColor.setColor((Integer) animation.getAnimatedValue()); + int color = (int) animation.getAnimatedValue(); + mBackgroundColorDrawable.setColor(color); + mBackgroundColor = color; } }); // Restore the translation @@ -329,4 +341,11 @@ public class TaskViewHeader extends FrameLayout { } } } + + public void setDimAlpha(int alpha) { + int color = Color.argb(alpha, 0, 0, 0); + mDimFilter.setColor(color); + mDimPaint.setColorFilter(mDimFilter); + setLayerType(LAYER_TYPE_HARDWARE, mDimPaint); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index fe36987..11ca103 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -16,9 +16,20 @@ package com.android.systemui.recents.views; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LightingColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; import com.android.systemui.recents.RecentsConfiguration; @@ -26,12 +37,30 @@ import com.android.systemui.recents.model.Task; /** The task thumbnail view */ -public class TaskViewThumbnail extends FixedSizeImageView { +public class TaskViewThumbnail extends View { + private final int mCornerRadius; + private final Matrix mScaleMatrix = new Matrix(); RecentsConfiguration mConfig; // Task bar clipping Rect mClipRect = new Rect(); + Paint mDrawPaint = new Paint(); + LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0); + private final RectF mBitmapRect = new RectF(); + private final RectF mLayoutRect = new RectF(); + private BitmapShader mBitmapShader; + private float mBitmapAlpha; + private float mDimAlpha; + private ValueAnimator mAlphaAnimator; + private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener + = new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mBitmapAlpha = (float) animation.getAnimatedValue(); + updateFilter(); + } + }; public TaskViewThumbnail(Context context) { this(context, null); @@ -48,12 +77,43 @@ public class TaskViewThumbnail extends FixedSizeImageView { public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mConfig = RecentsConfiguration.getInstance(); - setScaleType(ScaleType.FIT_XY); + mCornerRadius = mConfig.taskViewRoundedCornerRadiusPx; + mDrawPaint.setColorFilter(mLightingColorFilter); + mDrawPaint.setFilterBitmap(true); + mDrawPaint.setAntiAlias(true); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.drawRoundRect(0, + 0, + getWidth(), + getHeight(), + mCornerRadius, + mCornerRadius, + mDrawPaint); } @Override protected void onFinishInflate() { - setAlpha(0.9f); + mBitmapAlpha = 0.9f; + updateFilter(); + } + + private void updateFilter() { + int mul = (int) ((1.0f - mDimAlpha) * mBitmapAlpha * 255); + int add = (int) ((1.0f - mDimAlpha) * (1 - mBitmapAlpha) * 255); + if (mBitmapShader != null) { + mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul)); + mLightingColorFilter.setColorAdd(Color.argb(0, add, add, add)); + mDrawPaint.setColorFilter(mLightingColorFilter); + mDrawPaint.setColor(0xffffffff); + } else { + mDrawPaint.setColorFilter(null); + int grey = mul + add; + mDrawPaint.setColor(Color.argb(255, grey, grey, grey)); + } + invalidate(); } /** Updates the clip rect based on the given task bar. */ @@ -72,11 +132,8 @@ public class TaskViewThumbnail extends FixedSizeImageView { /** Binds the thumbnail view to the screenshot. */ boolean bindToScreenshot(Bitmap ss) { - if (ss != null) { - setImageBitmap(ss); - return true; - } - return false; + setImageBitmap(ss); + return ss != null; } /** Unbinds the thumbnail view from the screenshot. */ @@ -88,12 +145,49 @@ public class TaskViewThumbnail extends FixedSizeImageView { void rebindToTask(Task t) { if (t.thumbnail != null) { setImageBitmap(t.thumbnail); + } else { + setImageBitmap(null); + } + } + + public void setImageBitmap(Bitmap bm) { + if (bm != null) { + mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, + Shader.TileMode.CLAMP); + mDrawPaint.setShader(mBitmapShader); + mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight()); + updateBitmapScale(); + } else { + mBitmapShader = null; + mDrawPaint.setShader(null); } + updateFilter(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + mLayoutRect.set(0, 0, getWidth(), getHeight()); + updateBitmapScale(); + } + } + + private void updateBitmapScale() { + if (mBitmapShader != null) { + mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL); + mBitmapShader.setLocalMatrix(mScaleMatrix); + } + } + + public void setDimAlpha(float dimAlpha) { + mDimAlpha = dimAlpha; + updateFilter(); } /** Unbinds the thumbnail view from the task */ void unbindFromTask() { - setImageDrawable(null); + setImageBitmap(null); } /** Handles focus changes. */ @@ -112,10 +206,11 @@ public class TaskViewThumbnail extends FixedSizeImageView { /** Prepares for the enter recents animation. */ void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask) { if (isTaskViewLaunchTargetTask) { - setAlpha(1f); + mBitmapAlpha = 1f; } else { - setAlpha(mConfig.taskViewThumbnailAlpha); + mBitmapAlpha = mConfig.taskViewThumbnailAlpha; } + updateFilter(); } /** Animates this task thumbnail as it enters recents */ @@ -130,16 +225,32 @@ public class TaskViewThumbnail extends FixedSizeImageView { } /** Animates the thumbnail alpha. */ - void startFadeAnimation(float finalAlpha, int delay, int duration, Runnable postAnimRunnable) { + void startFadeAnimation(float finalAlpha, int delay, int duration, final Runnable postAnimRunnable) { + if (mAlphaAnimator != null) { + mAlphaAnimator.cancel(); + } + mAlphaAnimator = ValueAnimator.ofFloat(mBitmapAlpha, finalAlpha); + mAlphaAnimator.addUpdateListener(mAlphaUpdateListener); + mAlphaAnimator.setStartDelay(delay); + mAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); + mAlphaAnimator.setDuration(duration); + mAlphaAnimator.start(); if (postAnimRunnable != null) { - animate().withEndAction(postAnimRunnable); + mAlphaAnimator.addListener(new AnimatorListenerAdapter() { + public boolean mCancelled; + + @Override + public void onAnimationCancel(Animator animation) { + mCancelled = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!mCancelled) { + postAnimRunnable.run(); + } + } + }); } - animate() - .alpha(finalAlpha) - .setStartDelay(delay) - .setInterpolator(mConfig.fastOutSlowInInterpolator) - .setDuration(duration) - .withLayer() - .start(); } } |