学习笔记7


活动地址:CSDN21天学习挑战赛

创作计划


1,机缘

Android 9.0 10.0 Launcher3 时钟动态图标的定制化(时钟动态图标)

2,收获

1.概述

在定制化10.0的项目开发中,在Launcher3的app列表页,有时钟app的图标,由于图标是静态的
开发的需要要求调成动态图标,时刻显示时间,所以要把时钟图标替换成动态图标

如图:

2. 9.0 10.0时钟动态图标的定制化主要核心代码


packages/apps/Launcher3/src/com/android/launcher3/BubbleTextView.java

packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

3,日常

3 9.0 10.0时钟动态图标的定制化主要核心代码和功能实现

在Launcher3 workspace 第二屏app列表页中 默认的时钟app图标是静态图标 就是时间不会变化的
但这也显然不符合要求,时间是时刻都在变化的 下面就来定制化时钟动态图标

3.1 定义绘制时间图标类IconUtil.java


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;

}

}

​​​​​​​3.2.计算当前时间工具类 DateUtils.java


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;

}

}

3.3时钟工具类DeskClockUtil.java


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);

}

}

3.4.BubbleTextView.java中设置动态图标


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 DOT_SCALE_PROPERTY

= new Property(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 TEXT_ALPHA_PROPERTY

= new Property(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);

}

}
  1. 最终在applyIconAndLabel(ItemInfoWithIcon info)加载app的图标 名称等信息

  2. 所以实现时钟动态图标就是在这里

4. 9.0 10.0时钟动态图标的定制化功能实现


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);

}

}

5.在Launcher.java的onResume()和onPause()中分别开始和暂停


protected void onResume() {

......

/* begin /DeskClockUtil.getInstance().onResume(this);/ end */

if (mLauncherCallbacks != null) {

mLauncherCallbacks.onResume();

}

}

@Override

protected void onPause() {

/* begin /DeskClockUtil.getInstance().onPause();/ end */

....

}

​​​​​​​​​​​​​​

你可能感兴趣的:(android,学习)