diff options
author | Joe Onorato <joeo@android.com> | 2010-04-05 16:15:37 -0500 |
---|---|---|
committer | Joe Onorato <joeo@android.com> | 2010-04-05 16:16:40 -0500 |
commit | e58d1c4e4a03a41c9b8eee6b79304fbf85998d7d (patch) | |
tree | 693dca29449d575e35cd6e58e5f57fb56ceb26f5 /policy/com | |
parent | 466d77617ace8380ab8c52ede20790755d8ff092 (diff) | |
download | frameworks_base-e58d1c4e4a03a41c9b8eee6b79304fbf85998d7d.zip frameworks_base-e58d1c4e4a03a41c9b8eee6b79304fbf85998d7d.tar.gz frameworks_base-e58d1c4e4a03a41c9b8eee6b79304fbf85998d7d.tar.bz2 |
Redo the look of the recent apps switcher.
Change-Id: Icb523e2f5949c2b502aa8003aa14b7ac98a616f2
Diffstat (limited to 'policy/com')
3 files changed, 387 insertions, 46 deletions
diff --git a/policy/com/android/internal/policy/impl/IconUtilities.java b/policy/com/android/internal/policy/impl/IconUtilities.java new file mode 100644 index 0000000..99055cf --- /dev/null +++ b/policy/com/android/internal/policy/impl/IconUtilities.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008 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. + */ + +package com.android.internal.policy.impl; + +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.PaintDrawable; +import android.graphics.drawable.StateListDrawable; +import android.graphics.Bitmap; +import android.graphics.BlurMaskFilter; +import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.TableMaskFilter; +import android.graphics.Typeface; +import android.text.Layout.Alignment; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.util.DisplayMetrics; +import android.util.Log; +import android.content.res.Resources; +import android.content.Context; + +/** + * Various utilities shared amongst the Launcher's classes. + */ +final class IconUtilities { + private static final String TAG = "IconUtilities"; + + private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff }; + + private int mIconWidth = -1; + private int mIconHeight = -1; + private int mIconTextureWidth = -1; + private int mIconTextureHeight = -1; + + private final Paint mPaint = new Paint(); + private final Paint mBlurPaint = new Paint(); + private final Paint mGlowColorPressedPaint = new Paint(); + private final Paint mGlowColorFocusedPaint = new Paint(); + private final Rect mOldBounds = new Rect(); + private final Canvas mCanvas = new Canvas(); + private final DisplayMetrics mDisplayMetrics; + + private int mColorIndex = 0; + + public IconUtilities(Context context) { + final Resources resources = context.getResources(); + DisplayMetrics metrics = mDisplayMetrics = resources.getDisplayMetrics(); + final float density = metrics.density; + final float blurPx = 5 * density; + + mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size); + mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2); + + mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL)); + mGlowColorPressedPaint.setColor(0xffffc300); + mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); + mGlowColorFocusedPaint.setColor(0xffff8e00); + mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); + + ColorMatrix cm = new ColorMatrix(); + cm.setSaturation(0.2f); + + mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, + Paint.FILTER_BITMAP_FLAG)); + } + + public Drawable createIconDrawable(Drawable src) { + Bitmap scaled = createIconBitmap(src); + + StateListDrawable result = new StateListDrawable(); + + result.addState(new int[] { android.R.attr.state_focused }, + new BitmapDrawable(createSelectedBitmap(scaled, false))); + result.addState(new int[] { android.R.attr.state_pressed }, + new BitmapDrawable(createSelectedBitmap(scaled, true))); + result.addState(new int[0], new BitmapDrawable(scaled)); + + result.setBounds(0, 0, mIconTextureWidth, mIconTextureHeight); + return result; + } + + /** + * Returns a bitmap suitable for the all apps view. The bitmap will be a power + * of two sized ARGB_8888 bitmap that can be used as a gl texture. + */ + private Bitmap createIconBitmap(Drawable icon) { + int width = mIconWidth; + int height = mIconHeight; + + if (icon instanceof PaintDrawable) { + PaintDrawable painter = (PaintDrawable) icon; + painter.setIntrinsicWidth(width); + painter.setIntrinsicHeight(height); + } else if (icon instanceof BitmapDrawable) { + // Ensure the bitmap has a density. + BitmapDrawable bitmapDrawable = (BitmapDrawable) icon; + Bitmap bitmap = bitmapDrawable.getBitmap(); + if (bitmap.getDensity() == Bitmap.DENSITY_NONE) { + bitmapDrawable.setTargetDensity(mDisplayMetrics); + } + } + int sourceWidth = icon.getIntrinsicWidth(); + int sourceHeight = icon.getIntrinsicHeight(); + + if (sourceWidth > 0 && sourceWidth > 0) { + // There are intrinsic sizes. + if (width < sourceWidth || height < sourceHeight) { + // It's too big, scale it down. + final float ratio = (float) sourceWidth / sourceHeight; + if (sourceWidth > sourceHeight) { + height = (int) (width / ratio); + } else if (sourceHeight > sourceWidth) { + width = (int) (height * ratio); + } + } else if (sourceWidth < width && sourceHeight < height) { + // It's small, use the size they gave us. + width = sourceWidth; + height = sourceHeight; + } + } + + // no intrinsic size --> use default size + int textureWidth = mIconTextureWidth; + int textureHeight = mIconTextureHeight; + + final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight, + Bitmap.Config.ARGB_8888); + final Canvas canvas = mCanvas; + canvas.setBitmap(bitmap); + + final int left = (textureWidth-width) / 2; + final int top = (textureHeight-height) / 2; + + if (false) { + // draw a big box for the icon for debugging + canvas.drawColor(sColors[mColorIndex]); + if (++mColorIndex >= sColors.length) mColorIndex = 0; + Paint debugPaint = new Paint(); + debugPaint.setColor(0xffcccc00); + canvas.drawRect(left, top, left+width, top+height, debugPaint); + } + + mOldBounds.set(icon.getBounds()); + icon.setBounds(left, top, left+width, top+height); + icon.draw(canvas); + icon.setBounds(mOldBounds); + + return bitmap; + } + + private Bitmap createSelectedBitmap(Bitmap src, boolean pressed) { + final Bitmap result = Bitmap.createBitmap(mIconTextureWidth, mIconTextureHeight, + Bitmap.Config.ARGB_8888); + final Canvas dest = new Canvas(result); + + dest.drawColor(0, PorterDuff.Mode.CLEAR); + + int[] xy = new int[2]; + Bitmap mask = src.extractAlpha(mBlurPaint, xy); + + dest.drawBitmap(mask, xy[0], xy[1], + pressed ? mGlowColorPressedPaint : mGlowColorFocusedPaint); + + mask.recycle(); + + dest.drawBitmap(src, 0, 0, mPaint); + + return result; + } +} diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsBackground.java b/policy/com/android/internal/policy/impl/RecentApplicationsBackground.java new file mode 100644 index 0000000..7c99e87 --- /dev/null +++ b/policy/com/android/internal/policy/impl/RecentApplicationsBackground.java @@ -0,0 +1,152 @@ +/* + * 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. + * 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. + */ + +package com.android.internal.policy.impl; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; + +/** + * A vertical linear layout. However, instead of drawing the background + * behnd the items, it draws the background outside the items based on the + * padding. If there isn't enough room to draw both, it clips the background + * instead of the contents. + */ +public class RecentApplicationsBackground extends LinearLayout { + private static final String TAG = "RecentApplicationsBackground"; + + private boolean mBackgroundSizeChanged; + private Drawable mBackground; + private Rect mTmp0 = new Rect(); + private Rect mTmp1 = new Rect(); + + public RecentApplicationsBackground(Context context) { + this(context, null); + init(); + } + + public RecentApplicationsBackground(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + mBackground = getBackground(); + setBackgroundDrawable(null); + setPadding(0, 0, 0, 0); + setGravity(Gravity.CENTER); + } + + @Override + protected boolean setFrame(int left, int top, int right, int bottom) { + setWillNotDraw(false); + if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { + mBackgroundSizeChanged = true; + } + return super.setFrame(left, top, right, bottom); + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mBackground || super.verifyDrawable(who); + } + + @Override + protected void drawableStateChanged() { + Drawable d = mBackground; + if (d != null && d.isStateful()) { + d.setState(getDrawableState()); + } + super.drawableStateChanged(); + } + + @Override + public void draw(Canvas canvas) { + final Drawable background = mBackground; + if (background != null) { + if (mBackgroundSizeChanged) { + mBackgroundSizeChanged = false; + Rect chld = mTmp0; + Rect bkg = mTmp1; + mBackground.getPadding(bkg); + getChildBounds(chld); + // This doesn't clamp to this view's bounds, which is what we want, + // so that the drawing is clipped. + final int top = chld.top - bkg.top; + final int bottom = chld.bottom + bkg.bottom; + // The background here is a gradient that wants to + // extend the full width of the screen (whatever that + // may be). + int left, right; + if (false) { + // This limits the width of the drawable. + left = chld.left - bkg.left; + right = chld.right + bkg.right; + } else { + // This expands it to full width. + left = 0; + right = getRight(); + } + background.setBounds(left, top, right, bottom); + } + } + mBackground.draw(canvas); + + if (false) { + android.graphics.Paint p = new android.graphics.Paint(); + p.setColor(0x88ffff00); + canvas.drawRect(background.getBounds(), p); + } + canvas.drawARGB((int)(0.75*0xff), 0, 0, 0); + + super.draw(canvas); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mBackground.setCallback(this); + setWillNotDraw(false); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mBackground.setCallback(null); + } + + private void getChildBounds(Rect r) { + r.left = r.top = Integer.MAX_VALUE; + r.bottom = r.right = Integer.MIN_VALUE; + final int N = getChildCount(); + for (int i=0; i<N; i++) { + View v = getChildAt(i); + if (v.getVisibility() == View.VISIBLE) { + r.left = Math.min(r.left, v.getLeft()); + r.top = Math.min(r.top, v.getTop()); + r.right = Math.max(r.right, v.getRight()); + r.bottom = Math.max(r.bottom, v.getBottom()); + } + } + } +} diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java index c5aafa5..8287253 100644 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -44,14 +44,13 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener static private StatusBarManager sStatusBar; - private static final int NUM_BUTTONS = 6; + private static final int NUM_BUTTONS = 8; private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards - final View[] mButtons = new View[NUM_BUTTONS]; + final TextView[] mIcons = new TextView[NUM_BUTTONS]; View mNoAppsText; IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - private int mIconSize; public RecentApplicationsDialog(Context context) { @@ -77,26 +76,32 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); } - Window theWindow = getWindow(); - theWindow.requestFeature(Window.FEATURE_NO_TITLE); - theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, - WindowManager.LayoutParams.FLAG_DIM_BEHIND); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + Window window = getWindow(); + window.requestFeature(Window.FEATURE_NO_TITLE); + window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - theWindow.setTitle("Recents"); + window.setTitle("Recents"); setContentView(com.android.internal.R.layout.recent_apps_dialog); - mButtons[0] = findViewById(com.android.internal.R.id.button1); - mButtons[1] = findViewById(com.android.internal.R.id.button2); - mButtons[2] = findViewById(com.android.internal.R.id.button3); - mButtons[3] = findViewById(com.android.internal.R.id.button4); - mButtons[4] = findViewById(com.android.internal.R.id.button5); - mButtons[5] = findViewById(com.android.internal.R.id.button6); + final WindowManager.LayoutParams params = window.getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(params); + window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND); + + mIcons[0] = (TextView)findViewById(com.android.internal.R.id.button0); + mIcons[1] = (TextView)findViewById(com.android.internal.R.id.button1); + mIcons[2] = (TextView)findViewById(com.android.internal.R.id.button2); + mIcons[3] = (TextView)findViewById(com.android.internal.R.id.button3); + mIcons[4] = (TextView)findViewById(com.android.internal.R.id.button4); + mIcons[5] = (TextView)findViewById(com.android.internal.R.id.button5); + mIcons[6] = (TextView)findViewById(com.android.internal.R.id.button6); + mIcons[7] = (TextView)findViewById(com.android.internal.R.id.button7); mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); - for (View b : mButtons) { + for (TextView b: mIcons) { b.setOnClickListener(this); } } @@ -106,7 +111,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener */ public void onClick(View v) { - for (View b : mButtons) { + for (TextView b: mIcons) { if (b == v) { // prepare a launch intent and send it Intent intent = (Intent)b.getTag(); @@ -143,9 +148,9 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener super.onStop(); // dump extra memory we're hanging on to - for (View b : mButtons) { - setButtonAppearance(b, null, null); - b.setTag(null); + for (TextView icon: mIcons) { + icon.setCompoundDrawables(null, null, null, null); + icon.setTag(null); } if (sStatusBar != null) { @@ -172,12 +177,14 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), 0); + IconUtilities iconUtilities = new IconUtilities(getContext()); + // Performance note: Our android performance guide says to prefer Iterator when // using a List class, but because we know that getRecentTasks() always returns // an ArrayList<>, we'll use a simple index instead. - int button = 0; + int index = 0; int numTasks = recentTasks.size(); - for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) { + for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) { final ActivityManager.RecentTaskInfo info = recentTasks.get(i); // for debug purposes only, disallow first result to create empty lists @@ -204,39 +211,29 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener if (resolveInfo != null) { final ActivityInfo activityInfo = resolveInfo.activityInfo; final String title = activityInfo.loadLabel(pm).toString(); - final Drawable icon = activityInfo.loadIcon(pm); + Drawable icon = activityInfo.loadIcon(pm); if (title != null && title.length() > 0 && icon != null) { - final View b = mButtons[button]; - setButtonAppearance(b, title, icon); - b.setTag(intent); - b.setVisibility(View.VISIBLE); - b.setPressed(false); - b.clearFocus(); - ++button; + final TextView tv = mIcons[index]; + tv.setText(title); + icon = iconUtilities.createIconDrawable(icon); + tv.setCompoundDrawables(null, icon, null, null); + tv.setTag(intent); + tv.setVisibility(View.VISIBLE); + tv.setPressed(false); + tv.clearFocus(); + ++index; } } } // handle the case of "no icons to show" - mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE); + mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE); // hide the rest - for ( ; button < NUM_BUTTONS; ++button) { - mButtons[button].setVisibility(View.GONE); - } - } - - /** - * Adjust appearance of each icon-button - */ - private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) { - TextView tv = (TextView) theButton; - tv.setText(theTitle); - if (icon != null) { - icon.setBounds(0, 0, mIconSize, mIconSize); + for (; index < NUM_BUTTONS; ++index) { + mIcons[index].setVisibility(View.GONE); } - tv.setCompoundDrawables(null, icon, null, null); } /** |