Launcher90 新安装应用title 提示---小圆点

# Launcher90 新安装应用title 提示---小圆点

###    前言:

  纵观市面上的华为、小米、vivo手机 在桌面或者文件夹中有新安装应用时会在title左边显示一个小圆点(颜色主流为绿色)从而提示用户此应用为新安装的app,可能有以下原因吧: 有一定的导流作用 促使用户去打开此新安装的应用,从UI的角度 页面较为美观吧。


  先看下效果图:

### 方案和问题:

在sugar版本上可以看到实现方案为在icon的右上角绘制一个小圆点 表示新安装应用,在Icon上面绘制圆点好处为,iconsize 相同,画的小圆点类似角标可以准确确定位置 基本适用于所有应用。不会有位置偏移变化。

现在改为在新安装的应用title前面添加小圆点 提示,由于每个应用title长短不一,需要动态计算title长度 使小圆点等距离的美观显示在桌面上。看了小米的显示效果为 小圆点距离title的第一个字距离都相同,这样才美观。那么在draw 这个小圆点时 就需要动态计算title首字母的坐标了,这样才能根据不同的title动态等距离的显示小圆点,美观的展示给用户。

先看下所有APP 调试效果图。

会根据每个应用的title前面显示一个小圆点,距离需要等宽。

### 具体实现方案:

在新安装APP的title显示小圆点在BubbleTextView.java 类中实现,需要在桌面添加创建此icon shortcut时 增加判断是否是新安装应用。

首先看下shortcut 实现,

代码位置:Z:\work\Launcher90\src\com\android\launcher3\BubbleTextView.java

由于桌面文件夹和deep shortcut hotset都是继承BubbleTextView.java 所以在创建是需增加判断过滤。

protected void drawRemindIcon(Canvas canvas) {

        if (getTag() != null && getTag() instanceof ShortcutInfo) {

            ShortcutInfo info = (ShortcutInfo) getTag();

            DeviceProfile grid = mActivity.getDeviceProfile();

            int paddingTop = mIconSize;

            int paddingleft = mOffsetRemindLeft;

            int position = 0;

            Layout layout = getLayout();

            Rect bound = new Rect();

            int line = layout.getLineForOffset(position);

            layout.getLineBounds(line, bound);

            int yAxisTop = bound.top;//字符顶部y坐标

            int yAxisBottom = bound.bottom;//字符底部y坐标

            float xAxisLeft = layout.getPrimaryHorizontal(position);//字符左边x坐标

            float xAxisRight = layout.getSecondaryHorizontal(position);//字符右边x坐标

            if (mDisplay == DISPLAY_WORKSPACE) {

                paddingleft = (int) xAxisLeft;

                paddingTop = mIconSize + (yAxisBottom - yAxisTop) / 2 + 2 * grid.iconDrawablePaddingPx;

            } else if (mDisplay == DISPLAY_FOLDER) {

                paddingleft = (int) xAxisLeft - mOffsetRemindLeft;

                paddingTop = mIconSize + (yAxisBottom - yAxisTop) / 4 + grid.iconDrawablePaddingPx/2;

            } else if (mDisplay == DISPLAY_SHORTCUT) {

                isShowRemind = false;

            } else if (mDisplay == DISPLAY_WIDGET) {

                isShowRemind = false;

            }

            LogUtil.d(TAG, "yAxisTop:" + yAxisTop + "yAxisBottom" + yAxisBottom + "xAxisLeft:" + xAxisLeft + "xAxisRight" + xAxisRight + "grid.iconDrawablePaddingPx" + grid.iconDrawablePaddingPx);

            if (info.remind && isShowRemind && shouldTextBeVisible()) {

                canvas.save();

                canvas.drawBitmap(LauncherAppState.getInstance(mContext).getBitmapAndDrawableCache().getRemindIcon(), paddingleft, paddingTop, null);

                canvas.restore();

            }

        }

    }



    此段会增加判断只在桌面快捷方式 文件夹内部显示小圆点 ,文件夹前面的需要后面特殊处理。


    主要用到 Layout layout = getLayout();

            Rect bound = new Rect();

            int line = layout.getLineForOffset(position);

            layout.getLineBounds(line, bound);

            int yAxisTop = bound.top;//字符顶部y坐标

            int yAxisBottom = bound.bottom;//字符底部y坐标

            float xAxisLeft = layout.getPrimaryHorizontal(position);//字符左边x坐标

            float xAxisRight = layout.getSecondaryHorizontal(position);//字符右边x坐标

可以动态计算title最前面字符的左边,有了它就可以canvas.drawBitmap 了。

快捷方式实现了。

接下来看下文件夹的实现方式,文件夹需要特殊处理,要根据folder 内部是否有新安装应用,如果folder内部有新安装应用,在打开文件夹是显示在应用前面,当关闭文件夹时会显示子文件夹title的前面(由于文件夹name 是可以自己定义的需要动态计算显示在前面);


    先看下调试效果。




    源码位置:

    Z:\work\Launcher90\src\com\android\launcher3\folder\FolderIcon.java


    在dispatchDraw(Canvas canvas)方法中循环遍历下folder内部是否有新安装应用。


      int count = mInfo.contents.size();

        boolean needremind = false;

        for (int i=0; i<count; i++) {

            ShortcutInfo info = mInfo.contents.get(i);

            if (CustomConfigManager.getInstance().supportFolderIconUnread) {

                if (info.unreadNum > 0) {

                    needremind = false;

                    break;

                }

            }

            if (info.remind) {

                needremind = true;

                if (CustomConfigManager.getInstance().supportFolderIconUnread) {

                    continue;

                }else {

                    break;

                }

            }

        }

        if (needremind) {

            drawFolderRemind(canvas);

        }



        private void drawFolderRemind(Canvas canvas) {

        canvas.save();

        int textureWidth = this.getWidth();

        int paddingTop = this.getPaddingTop();

        int paddingleft = mOffsetRemindLeft;

        DeviceProfile grid = mLauncher.getDeviceProfile();

        DisplayMetrics dm = mLauncher.getResources().getDisplayMetrics();

        int position = 0;

        if (mFolderName == null) {

            return;

        }

        Layout layout = mFolderName.getLayout();

        Rect bound = new Rect();

        int line = layout.getLineForOffset(position);

        layout.getLineBounds(line, bound);

        int yAxisTop = bound.top;//字符顶部y坐标

        int xAxisCenter = bound.centerX();//字符顶部y坐标

        int yAxisBottom = bound.bottom;//字符底部y坐标

        float xAxisLeft = layout.getPrimaryHorizontal(position);//字符左边x坐标

        float xAxisRight = layout.getSecondaryHorizontal(position);//字符右边x坐标

        paddingTop = grid.iconSizePx + (yAxisBottom - yAxisTop) / 2 + 2 * grid.iconDrawablePaddingPx;

        paddingleft = textureWidth/2 - (xAxisCenter - (int) xAxisLeft)-mOffsetRemindLeft;


        canvas.drawBitmap(LauncherAppState.getInstance(mLauncher).getBitmapAndDrawableCache().getRemindIcon(), paddingleft, paddingTop, null);

        canvas.restore();

    }



    和shortcut 创建流程基本类似 需要计算文件夹name左边,在调试过程中 发现 文件夹的name首字母坐标不是left值 需要this.getWidth()/2 减去 name中心坐标和首字母坐标,会随首字母坐标变left变小.


    到此显示布局逻辑基本实现了接下来需要控制判断哪些是新安装的应用才显示。



### 如何判断新安装应用:

源码位置:

Z:\work\Launcher90\src\com\android\launcher3\Workspace.java

Z:\work\Launcher90\src\com\ape\launcher3\MyosLauncher.java

本次实现方案没有保存在数据库中,在监听新安装应用时 保存此应用的包名到sp,

然后再luncher onresume 或者

public void finishBindingItems() 分别刷新下。

  public void refreshRemindIcon() {


        LogUtil.d(TAG, "refreshRemindIcon()");

        Set<String> set = DownloadRemind.getAllReminValue(MyosLauncher.this);

        final HashMap<String, Integer> remindMap = new HashMap<>();

        LogUtil.d(TAG, "remindMap");

        for (String s : set) {

            int state = DownloadRemind.isRemindApp(MyosLauncher.this, s) ? 0 : 1;

            LogUtil.d(TAG, "refreshRemindIcon : packageName = " + s + ", state = " + state);

            remindMap.put(s, state);

        }

        mHandler.post(new Runnable() {

            public void run() {

                if (mWorkspace != null) {

                    mWorkspace.updateShortcutsAndFoldersRemind(remindMap);

                }

            }

        });

    }

刷新遍历 ShortcutInfo 、FolderInfo、Hotseat是否包含在sp中的包名remind info 信息。

public void updateShortcutsAndFoldersRemind(HashMap<String, Integer> remindMap) {

        final ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();

        int childCount = 0;

        View view = null;

        Object tag = null;

        for (ShortcutAndWidgetContainer layout : childrenLayouts) {

            childCount = layout.getChildCount();

            for (int j = 0; j < childCount; j++) {

                view = layout.getChildAt(j);

                tag = view.getTag();

                if (tag instanceof ShortcutInfo) {

                    final ShortcutInfo info = (ShortcutInfo) tag;

                    final Intent intent = info.intent;

                    final ComponentName componentName = intent.getComponent();

                    if (componentName != null && componentName.getPackageName() != null

                            && remindMap.containsKey(componentName.getPackageName())) {

                        ////this is remind app

                        if (remindMap.get(componentName.getPackageName()) == 0) {

                            info.remind = true;

                        } else {

                            info.remind = false;

                        }

                    }

                    ((BubbleTextView)view).invalidate();

                    //((BubbleTextView) view).mFavorite.invalidate();

                } else if (tag instanceof FolderInfo) {

                    ((FolderIcon) view).updateFolderRemind(remindMap);

                    ((FolderIcon) view).invalidate();

                }

            }

        }

        mLauncher.getHotseat().updateRemindApps(remindMap);

    }




### title圆点如何消失:

  目前处理 判别应用是否进入新应用,为从桌面点击 startactivity 即认为不是新应用了需要移除标志位。


  public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {


        boolean success = super.startActivitySafely(v, intent, item);

        if (success && v instanceof BubbleTextView) {

            // This is set to the view that launched the activity that navigated the user away

            // from launcher. Since there is no callback for when the activity has finished

            // launching, enable the press state and keep this reference to reset the press

            // state when we return to launcher.

            BubbleTextView btv = (BubbleTextView) v;

            btv.setStayPressed(true);

            setOnResumeCallback(btv);

            if (DownloadRemind.isRemindApp(this, intent.getComponent().getPackageName())) {

                DownloadRemind.setDownloadAppsRemind(this, intent.getComponent().getPackageName(), false);

            }

            LogUtil.d(TAG, "startActivitySafely success:" + success + "PackageName:" + intent.getComponent().getPackageName());

        }

        return success;

    }


  设置对应的包名 value 为false;



  以上为新安装应用的title 小圆点draw位置、显示、和消失基本逻辑 方案。方法很多如有好的更优的方法 欢迎指正。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容