Adding a circular progress bar for preloader icons
Change-Id: I1b5ba61c01a16a8cb5d3f9e31f827f8c99a1ffc9
This commit is contained in:
parent
f599ccfe96
commit
3484638cad
|
@ -52,3 +52,8 @@
|
|||
-keep class com.android.launcher3.MemoryDumpActivity {
|
||||
*;
|
||||
}
|
||||
|
||||
-keep class com.android.launcher3.PreloadIconDrawable {
|
||||
public float getAnimationProgress();
|
||||
public void setAnimationProgress(float);
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -1,22 +0,0 @@
|
|||
<?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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<integer name="promise_icon_alpha">127</integer>
|
||||
</resources>
|
|
@ -136,7 +136,8 @@ public class BubbleTextView extends TextView {
|
|||
setContentDescription(info.contentDescription);
|
||||
}
|
||||
setTag(info);
|
||||
if (info.isPromise()) {
|
||||
|
||||
if (info.wasPromise) {
|
||||
applyState();
|
||||
}
|
||||
}
|
||||
|
@ -431,42 +432,55 @@ public class BubbleTextView extends TextView {
|
|||
}
|
||||
|
||||
public void applyState() {
|
||||
int alpha = getResources().getInteger(R.integer.promise_icon_alpha);
|
||||
final int progressLevel;
|
||||
final int state = getState();
|
||||
if (DEBUG) Log.d(TAG, "applying icon state: " + state);
|
||||
|
||||
switch(state) {
|
||||
case ShortcutInfo.PACKAGE_STATE_DEFAULT:
|
||||
super.setText(mDefaultText);
|
||||
alpha = 255;
|
||||
progressLevel = 100;
|
||||
break;
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_ENQUEUED:
|
||||
setText(R.string.package_state_enqueued);
|
||||
progressLevel = 0;
|
||||
break;
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_DOWNLOADING:
|
||||
setText(R.string.package_state_downloading);
|
||||
// TODO(sunnygoyal): fix progress
|
||||
progressLevel = 30;
|
||||
break;
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_INSTALLING:
|
||||
setText(R.string.package_state_installing);
|
||||
progressLevel = 100;
|
||||
break;
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_ERROR:
|
||||
setText(R.string.package_state_error);
|
||||
progressLevel = 0;
|
||||
break;
|
||||
|
||||
case ShortcutInfo.PACKAGE_STATE_UNKNOWN:
|
||||
default:
|
||||
progressLevel = 0;
|
||||
setText(R.string.package_state_unknown);
|
||||
break;
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "setting icon alpha to: " + alpha);
|
||||
|
||||
Drawable[] drawables = getCompoundDrawables();
|
||||
for (int i = 0; i < drawables.length; i++) {
|
||||
if (drawables[i] != null) {
|
||||
drawables[i].setAlpha(alpha);
|
||||
Drawable top = drawables[1];
|
||||
if ((top != null) && !(top instanceof PreloadIconDrawable)) {
|
||||
top = new PreloadIconDrawable(top, getResources());
|
||||
setCompoundDrawables(drawables[0], top, drawables[2], drawables[3]);
|
||||
}
|
||||
if (top != null) {
|
||||
top.setLevel(progressLevel);
|
||||
if ((top instanceof PreloadIconDrawable)
|
||||
&& (state == ShortcutInfo.PACKAGE_STATE_DEFAULT)) {
|
||||
((PreloadIconDrawable) top).maybePerformFinishedAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -605,7 +605,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
computePreviewDrawingParams(mAnimParams.drawable);
|
||||
} else {
|
||||
v = (TextView) items.get(0);
|
||||
d = v.getCompoundDrawables()[1];
|
||||
d = getTopDrawable(v);
|
||||
computePreviewDrawingParams(d);
|
||||
}
|
||||
|
||||
|
@ -614,7 +614,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
for (int i = nItemsInPreview - 1; i >= 0; i--) {
|
||||
v = (TextView) items.get(i);
|
||||
if (!mHiddenItems.contains(v.getTag())) {
|
||||
d = v.getCompoundDrawables()[1];
|
||||
d = getTopDrawable(v);
|
||||
mParams = computePreviewItemDrawingParams(i, mParams);
|
||||
mParams.drawable = d;
|
||||
drawPreviewItem(canvas, mParams);
|
||||
|
@ -625,6 +625,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
}
|
||||
}
|
||||
|
||||
private Drawable getTopDrawable(TextView v) {
|
||||
Drawable d = v.getCompoundDrawables()[1];
|
||||
return (d instanceof PreloadIconDrawable) ? ((PreloadIconDrawable) d).mIcon : d;
|
||||
}
|
||||
|
||||
private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
|
||||
final Runnable onCompleteRunnable) {
|
||||
final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
|
||||
|
|
|
@ -3047,6 +3047,7 @@ public class LauncherModel extends BroadcastReceiver
|
|||
info.setIcon(mIconCache.getIcon(intent, info.title.toString(), info.user));
|
||||
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
|
||||
info.restoredIntent = intent;
|
||||
info.wasPromise = true;
|
||||
info.setState(ShortcutInfo.PACKAGE_STATE_UNKNOWN);
|
||||
return info;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
package com.android.launcher3;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
class PreloadIconDrawable extends Drawable {
|
||||
private static final float ANIMATION_PROGRESS_STOPPED = -1.0f;
|
||||
private static final float ANIMATION_PROGRESS_STARTED = 0f;
|
||||
private static final float ANIMATION_PROGRESS_COMPLETED = 1.0f;
|
||||
|
||||
private static final float ICON_SCALE_FACTOR = 0.6f;
|
||||
|
||||
private static Bitmap sProgressBg, sProgressFill;
|
||||
|
||||
private final Rect mCanvasClipRect = new Rect();
|
||||
private final RectF mRect = new RectF();
|
||||
private final Path mProgressPath = new Path();
|
||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||
|
||||
final Drawable mIcon;
|
||||
|
||||
/**
|
||||
* Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon
|
||||
* is shown with no progress bar.
|
||||
*/
|
||||
private int mProgress = 0;
|
||||
private boolean mPathChanged;
|
||||
|
||||
private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
|
||||
private ObjectAnimator mAnimator;
|
||||
|
||||
public PreloadIconDrawable(Drawable icon, Resources res) {
|
||||
mIcon = icon;
|
||||
|
||||
setBounds(icon.getBounds());
|
||||
mPathChanged = false;
|
||||
|
||||
if (sProgressBg == null) {
|
||||
sProgressBg = BitmapFactory.decodeResource(res, R.drawable.bg_preloader);
|
||||
}
|
||||
if (sProgressFill == null) {
|
||||
sProgressFill = BitmapFactory.decodeResource(res, R.drawable.bg_preloader_progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
final Rect r = getBounds();
|
||||
if (canvas.getClipBounds(mCanvasClipRect) && !Rect.intersects(mCanvasClipRect, r)) {
|
||||
// The draw region has been clipped.
|
||||
return;
|
||||
}
|
||||
final float iconScale;
|
||||
|
||||
if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED)
|
||||
&& (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) {
|
||||
mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255));
|
||||
canvas.drawBitmap(sProgressBg, null, r, mPaint);
|
||||
canvas.drawBitmap(sProgressFill, null, r, mPaint);
|
||||
iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress;
|
||||
|
||||
} else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) {
|
||||
mPaint.setAlpha(255);
|
||||
iconScale = ICON_SCALE_FACTOR;
|
||||
canvas.drawBitmap(sProgressBg, null, r, mPaint);
|
||||
|
||||
if (mProgress >= 100) {
|
||||
canvas.drawBitmap(sProgressFill, null, r, mPaint);
|
||||
} else if (mProgress > 0) {
|
||||
if (mPathChanged) {
|
||||
mProgressPath.reset();
|
||||
mProgressPath.moveTo(r.exactCenterX(), r.centerY());
|
||||
|
||||
mRect.set(r);
|
||||
mProgressPath.arcTo(mRect, -90, mProgress * 3.6f);
|
||||
mProgressPath.close();
|
||||
mPathChanged = false;
|
||||
}
|
||||
|
||||
canvas.save();
|
||||
canvas.clipPath(mProgressPath);
|
||||
canvas.drawBitmap(sProgressFill, null, r, mPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
} else {
|
||||
iconScale = 1;
|
||||
}
|
||||
|
||||
canvas.save();
|
||||
canvas.scale(iconScale, iconScale, r.exactCenterX(), r.exactCenterY());
|
||||
mIcon.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
mIcon.setBounds(bounds);
|
||||
mPathChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mIcon.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
mIcon.setColorFilter(cf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onLevelChange(int level) {
|
||||
mProgress = level;
|
||||
mPathChanged = true;
|
||||
|
||||
// Stop Animation
|
||||
if (mAnimator != null) {
|
||||
mAnimator.cancel();
|
||||
mAnimator = null;
|
||||
}
|
||||
mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
|
||||
|
||||
invalidateSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the finish animation if it is has not been run after last level change.
|
||||
*/
|
||||
public void maybePerformFinishedAnimation() {
|
||||
if (mAnimationProgress > ANIMATION_PROGRESS_STOPPED) {
|
||||
return;
|
||||
}
|
||||
if (mAnimator != null) {
|
||||
mAnimator.cancel();
|
||||
}
|
||||
setAnimationProgress(ANIMATION_PROGRESS_STARTED);
|
||||
mAnimator = ObjectAnimator.ofFloat(this, "animationProgress",
|
||||
ANIMATION_PROGRESS_STARTED, ANIMATION_PROGRESS_COMPLETED);
|
||||
mAnimator.start();
|
||||
}
|
||||
|
||||
public void setAnimationProgress(float progress) {
|
||||
if (progress != mAnimationProgress) {
|
||||
mAnimationProgress = progress;
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
public float getAnimationProgress() {
|
||||
return mAnimationProgress;
|
||||
}
|
||||
}
|
|
@ -16,13 +16,9 @@
|
|||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -96,6 +92,11 @@ public class ShortcutInfo extends ItemInfo {
|
|||
*/
|
||||
Intent restoredIntent;
|
||||
|
||||
/**
|
||||
* This is set once to indicate that it was a promise info at some point of its life.
|
||||
*/
|
||||
boolean wasPromise = false;
|
||||
|
||||
ShortcutInfo() {
|
||||
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
|
||||
}
|
||||
|
@ -119,7 +120,7 @@ public class ShortcutInfo extends ItemInfo {
|
|||
}
|
||||
}
|
||||
|
||||
ShortcutInfo(Intent intent, CharSequence title, String contentDescrition,
|
||||
ShortcutInfo(Intent intent, CharSequence title, String contentDescription,
|
||||
Bitmap icon, UserHandleCompat user) {
|
||||
this();
|
||||
this.intent = intent;
|
||||
|
|
Loading…
Reference in New Issue