活动地址:CSDN21天学习挑战赛
在定制化10.0的项目开发中,在Launcher3的app列表页,有时钟app的图标,由于图标是静态的开发的需要要求调成动态图标,时刻显示时间,所以要把时钟图标替换成动态图标。
packages/apps/Launcher3/src/com/android/launcher3/BubbleTextView.java
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
在Launcher3 workspace 第二屏app列表页中 默认的时钟app图标是静态图标 就是时间不会变化的但这也显然不符合要求,时间是时刻都在变化的。
package com.android.launcher3;
import android.content.Context;
import android.graphics.*;
import com.android.launcher3.R;
public class IconUtil {
private static final String TAG = "IconUtil";
private static Bitmap getBitmap(Context context, int res) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
return BitmapFactory.decodeResource(context.getResources(), res, options);
}
public static Bitmap getDeskClockIcon(Context context) {
Bitmap empty = getBitmap(context, R.drawable.icon_time);
int x = empty.getWidth();
int y = empty.getHeight();
Bitmap deskClock = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(deskClock);
Paint paint = new Paint();
paint.setAntiAlias(true);
canvas.drawBitmap(empty, 0, 0, paint);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(30);
paint.setColor(Color.parseColor("#FFA500"));
int radius = 200;
int cx = x / 2;
int cy = y / 2;
int hour = Integer.parseInt(DateUtils.getCurrentHour());
int min = Integer.parseInt(DateUtils.getCurrentMin());
//时针的角度,这里是整点的角度。因为0°是从3点开始,所以这里减90°,从9点开始计算角度
int drgeeHour = hour * 30 - 90;
if (drgeeHour < 0) {
drgeeHour += 360;
}
// 加上时针在两个整点之间的角度,一分钟在分针上是6°,在时针上是min * 6 / 12
drgeeHour += min * 6 / 12;
//时针 针尖的x y坐标,相当于已知圆心坐标和半径,求圆上任意一点的坐标
int xHour = (int) (cx + radius * Math.cos(drgeeHour * 3.14 / 180));
int yHour = (int) (cy + radius * Math.sin(drgeeHour * 3.14 / 180));
canvas.drawLine(xHour, yHour, cx, cy, paint);
//分针的长度
radius = 260;
paint.setStrokeWidth(20);
paint.setColor(Color.RED);
//分针的角度
int drgeeMin = min * 6 - 90;
if (drgeeMin < 0) {
drgeeMin += 360;
}
//分针 针尖的x y坐标
int x1 = (int) (cx + radius * Math.cos(drgeeMin * Math.PI / 180));
int y1 = (int) (cy + radius * Math.sin(drgeeMin * Math.PI / 180));
canvas.drawLine(x1, y1, cx, cy, paint);
return deskClock;
}
}
package com.android.launcher3;
import java.text.SimpleDateFormat;
public class DateUtils {
public static String getCurrentDay() {
SimpleDateFormat format = new SimpleDateFormat("dd");
Long t = new Long(System.currentTimeMillis());
String d = format.format(t);
return d;
}
public static String getCurrentSecond() {
SimpleDateFormat format = new SimpleDateFormat("ss");
Long t = new Long(System.currentTimeMillis());
String d = format.format(t);
return d;
}
public static String getCurrentMin() {
SimpleDateFormat format = new SimpleDateFormat("mm");
Long t = new Long(System.currentTimeMillis());
String d = format.format(t);
return d;
}
public static String getCurrentHour() {
SimpleDateFormat format = new SimpleDateFormat("HH");
Long t = new Long(System.currentTimeMillis());
String d = format.format(t);
return d;
}
}
package com.android.launcher3;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import com.android.launcher3.LauncherSettings;
public class DeskClockUtil {
private OnDeskClockIconChangeListener mListener;
private boolean mIsResume;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 100) {
Message msg1 = new Message();
msg1.what = 100;
msg1.obj = msg.obj;
mHandler.sendMessageDelayed(msg1, 60000);
if (mListener != null) {
mListener.onChange(IconUtil.getDeskClockIcon((Context) msg.obj));
}
}
}
};
private static DeskClockUtil sInstance;
private DeskClockUtil() {
}
public static DeskClockUtil getInstance() {
if (sInstance == null) {
sInstance = new DeskClockUtil();
}
return sInstance;
}
private void refresh(Context context) {
if (mListener != null) {
mListener.onChange(IconUtil.getDeskClockIcon(context));
}
if (mHandler.hasMessages(100)) {
mHandler.removeMessages(100);
}
Message msg = new Message();
msg.what = 100;
msg.obj = context;
mHandler.sendMessageDelayed(msg,
1000 * (60 - Integer.parseInt(DateUtils.getCurrentSecond())));
}
public void onResume(Context context) {
mIsResume = true;
refresh(context);
}
public void onPause() {
mIsResume = false;
mHandler.removeMessages(100);
}
public void setListener(OnDeskClockIconChangeListener listener,Context context) {
mListener = listener;
if (mIsResume) {
refresh(context);
}
}
public interface OnDeskClockIconChangeListener {
void onChange(Bitmap icon);
}
}
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback {
private static final int DISPLAY_WORKSPACE = 0;
private static final int DISPLAY_ALL_APPS = 1;
private static final int DISPLAY_FOLDER = 2;
private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
= new Property<BubbleTextView, Float>(Float.TYPE, "dotScale") {
@Override
public Float get(BubbleTextView bubbleTextView) {
return bubbleTextView.mDotParams.scale;
}
@Override
public void set(BubbleTextView bubbleTextView, Float value) {
bubbleTextView.mDotParams.scale = value;
bubbleTextView.invalidate();
}
};
public static final Property<BubbleTextView, Float> TEXT_ALPHA_PROPERTY
= new Property<BubbleTextView, Float>(Float.class, "textAlpha") {
@Override
public Float get(BubbleTextView bubbleTextView) {
return bubbleTextView.mTextAlpha;
}
@Override
public void set(BubbleTextView bubbleTextView, Float alpha) {
bubbleTextView.setTextAlpha(alpha);
}
};
private final ActivityContext mActivity;
private Drawable mIcon;
private final boolean mCenterVertically;
private final CheckLongPressHelper mLongPressHelper;
private final StylusEventHelper mStylusEventHelper;
private final float mSlop;
private final boolean mLayoutHorizontal;
private final int mIconSize;
private float mIconTextSize;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mIsIconVisible = true;
@ViewDebug.ExportedProperty(category = "launcher")
private int mTextColor;
@ViewDebug.ExportedProperty(category = "launcher")
private float mTextAlpha = 1;
@ViewDebug.ExportedProperty(category = "launcher")
private DotInfo mDotInfo;
private DotRenderer mDotRenderer;
@ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
private DotRenderer.DrawParams mDotParams;
private Animator mDotScaleAnim;
private boolean mForceHideDot;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mStayPressed;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mIgnorePressedStateChange;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mDisableRelayout = false;
private IconLoadRequest mIconLoadRequest;
public BubbleTextView(Context context) {
this(context, null, 0);
}
public BubbleTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mActivity = ActivityContext.lookupContext(context);
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
final int defaultIconSize;
if (display == DISPLAY_WORKSPACE) {
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
defaultIconSize = grid.iconSizePx;
mIconTextSize = grid.iconTextSizePx;
} else if (display == DISPLAY_ALL_APPS) {
DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
mIconTextSize = grid.allAppsIconTextSizePx;
} else if (display == DISPLAY_FOLDER) {
DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
defaultIconSize = grid.folderChildIconSizePx;
mIconTextSize = grid.folderChildTextSizePx;
} else {
defaultIconSize = mActivity.getDeviceProfile().iconSizePx;
mIconTextSize = mActivity.getWallpaperDeviceProfile().iconTextSizePx;
}
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
defaultIconSize);
a.recycle();
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
mDotParams = new DotRenderer.DrawParams();
setMaxLines(mActivity.getDeviceProfile().maxIconLabelLines);
setEllipsize(TruncateAt.END);
setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
setTextAlpha(1f);
}
/**
* Applies the item info if it is same as what the view is pointing to currently.
*/
@Override
public void reapplyItemInfo(ItemInfoWithIcon info) {
if (getTag() == info) {
mIconLoadRequest = null;
mDisableRelayout = true;
// Optimization: Starting in N, pre-uploads the bitmap to RenderThread.
info.iconBitmap.prepareToDraw();
if (info instanceof AppInfo) {
//加载app图标
applyFromApplicationInfo((AppInfo) info);
} else if (info instanceof WorkspaceItemInfo) {
applyFromWorkspaceItem((WorkspaceItemInfo) info);
mActivity.invalidateParent(info);
} else if (info instanceof PackageItemInfo) {
applyFromPackageItemInfo((PackageItemInfo) info);
}
mDisableRelayout = false;
}
}
reapplyItemInfo()负责加载appInfo workspaceitem PackageItemInfo的相关信息
public void applyFromApplicationInfo(AppInfo info) {
applyIconAndLabel(info);
// We don't need to check the info since it's not a WorkspaceItemInfo
super.setTag(info);
// Verify high res immediately
verifyHighRes();
if (info instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;
applyProgressLevel(promiseAppInfo.level);
}
applyDotState(info, false /* animate */);
}
public void applyFromPackageItemInfo(PackageItemInfo info) {
applyIconAndLabel(info);
// We don't need to check the info since it's not a WorkspaceItemInfo
super.setTag(info);
// Verify high res immediately
verifyHighRes();
}
private void applyIconAndLabel(ItemInfoWithIcon info) {
FastBitmapDrawable iconDrawable = DrawableFactory.INSTANCE.get(getContext())
.newIcon(getContext(), info);
mDotParams.color = IconPalette.getMutedColor(info.iconColor, 0.54f);
setIcon(iconDrawable);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.isDisabled()
? getContext().getString(R.string.disabled_app_label, info.contentDescription)
: info.contentDescription);
}
}
private void applyIconAndLabel(ItemInfoWithIcon info) {
String pkgname = "";
if (info.getIntent() != null && info.getIntent().getComponent() != null) {
pkgname = info.getIntent().getComponent().getPackageName();
}
android.util.Log.e("Launcher3","pkgname:"+pkgname);
FastBitmapDrawable iconDrawable = null;
if(pkgname.equals("com.android.deskclock")){
DeskClockUtil.getInstance().setListener(new DeskClockUtil.OnDeskClockIconChangeListener() {
@Override
public void onChange(Bitmap icon) {
FastBitmapDrawable deskiconDrawable = new FastBitmapDrawable(icon);
android.util.Log.e("Launcher3","deskiconDrawable:"+deskiconDrawable+"--icon:"+icon);
if(deskiconDrawable!=null)setIcon(deskiconDrawable);
}
}, getContext());
}else{
iconDrawable = DrawableFactory.INSTANCE.get(getContext())
.newIcon(getContext(), info);
}
//FastBitmapDrawable iconDrawable = DrawableFactory.INSTANCE.get(getContext())
//.newIcon(getContext(), info);
mDotParams.color = IconPalette.getMutedColor(info.iconColor, 0.54f);
if(iconDrawable!=null)setIcon(iconDrawable);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.isDisabled()
? getContext().getString(R.string.disabled_app_label, info.contentDescription)
: info.contentDescription);
}
}
protected void onResume() {
......
/* begin /DeskClockUtil.getInstance().onResume(this);/ end */
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
}
}
@Override
protected void onPause() {
/* begin /DeskClockUtil.getInstance().onPause();/ end */
....
}