Badge分析&如何逼死处女座

by admin on 2018年9月24日
  • CoreText实现图文混排
  • CoreText实现图文混排之点击事件
  • CoreText实现图文混排之言环绕及点击算法
  • CoreText实现图文混排之尺寸估算及文件选择

方法二

https://github.com/shafty023/SamsungBadger


LG Badge

Samsung好基友,三星球能就此的,LG几乎都好用,连Bug都一致。

当选效果

这吧是就发出童靴问我的,当时吧是千篇一律面子懵逼。因为这事物本身当研TextView的当儿真的是想研究了得,不过系统立即部分内容连无明白,也惟有经过runtime追踪到TextView是借助UITextSelectionView这么一个私有类完成的,更多之资料也未是过剩。

既是无可知经过系统虽然有接近实现相关要求,那么我们还是自己分析一下要求。事实上我们无非待拿到每个字形的尺码,然后以上方挂一个淡蓝色的覆盖层即可模拟出选中作用。至于用到每个字形的尺码,这里我们靠CoreText还是足以成功的。

一直司机以DWCoreTextLabel中召开了之类的一样交汇逻辑封装:

DWCoreTextLayout

DWCoreTextLayout对象为CTFrame对象开展初始化,后自动分析出全CTLine、CTRun及各一个字形,并获取尺寸等其连带消息。并且每个包装类包装类之间是一个类于链表的结构,用于快速获得上一个或者生一个应和的Line、Run或者Glyph。并且Line以数组形式持有者Run,而Run又因死引用形式引用在Line,Run与Glyph之间吧维持正同的干。有及时这样的干是,就足以迅速的把屏幕被的点转换为对应之配。

产生了DWCoreTextLayout对象的留存,我们会得到每个字形对应的尺码,也就是可知获得一段子文字所对应的尺码,只要以对应尺寸出覆盖淡蓝色选择遮罩层即可。具体贯彻代码也未掉,老车手以是单提供思路,想看落实之言语还是错过DWCoreTextLayout.m中扣现实代码吧。

自思念挂遮罩层各位童靴应该不在言辞下,然而此还有一定啊就是哪些进入选中状态。TextView中是当我们在文字上双击文字后上选择状态,那咱们捕捉双击状态的下或是双击手势,要么是touchBegan方法处理。我们了解我们的Label控件被呢亲笔上加点击事件不时靠的凡touchBegan系列措施,不论是那种方式我们且如拍卖好不无关系逻辑,否则会存在冲突。这里一直司机的建议是因为双击手势唤起选择状态,并且用Label的点击事件有关touchEnd方法被触发。这是为双击手势而生效取消touchesEnd的回调,这样尽管避免了冲突。


Github

遗忘发地址了
https://github.com/xuyisheng/ShortcutHelper

废话这么多,在及时进入正题,所以今天的博客中君拿会看出如下内容:

  • CoreText做排版时怎样进行尺寸估算
  • 怎么兑现TextView中接近之文本选择效果
  • CoreText一些API中有业已知bug

Samsung Badge

同体面庄重

锤子

锤子很遗憾,使用的凡原生Launcher进行的修改,只有System
App具有取角标的权柄。

顿时篇稿子的机要目的是回复童靴们的问题,因为起童靴问了我尺寸估算和文本选择的题材,当时由于实在没研究那么上面内容所以应的上都没给来解决方案,只供思路。后来没事下来便钻了一晃即时片上面内容,研究后就是管研究结果放出去,也总算让新兴的童靴们一个思路吧。至于问我之那么片独童靴,我实际想不起来你俩是哪个了,没法私信你俩了,抱歉。

方法一

由此三星Launcher自己之播音,来让使用添加角标:

/**
 * 设置三星的Badge
 *
 * @param context context
 * @param count   count
 */
private static void setBadgeOfSumsung(Context context, int count) {
    // 获取你当前的应用
    String launcherClassName = getLauncherClassName(context);
    if (launcherClassName == null) {
        return;
    }
    Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
    intent.putExtra("badge_count", count);
    intent.putExtra("badge_count_package_name", context.getPackageName());
    intent.putExtra("badge_count_class_name", launcherClassName);
    context.sendBroadcast(intent);
}

是办法无需要外权力,只需要知道App的包名和类名。用,你当可以在程序中让其它任意一个App设置任意数量的角标,而且从不其余提示,是的,很流氓,谁说非是吗,当然别说凡是自我报您的,你就算所而是百度的。例如:

intent.putExtra("badge_count_package_name", "com.tencent.mobileqq");
    intent.putExtra("badge_count_class_name", "com.tencent.mobileqq.activity.SplashActivity");

将包名和好像名用QQ的轮换下,然后您不怕可以任意、为所待以。

DWCoreTextLabel

然第三篇中留有Demo地址,目的就想方便童鞋们直接下载demo,不要再提问我一旦了,所以于前头片篇中显的位置还发出扬言demo在第三篇稿子中。但是还是起童靴直接留言要demo的,想必一定是老司机口水话太多没耐心看下来吧。但是老司机真的觉得你连原理看都未看同样肉眼的讲话使demo你为扣无明白,所以当当下声明一下咔嚓,今天朝着后还使demo的童靴,不好意思啊,我无见面恢复的。

自己产生特权


Badge分析

所谓Badge,原本是iOS上之一个功效,但是被Android抄的大半了,也不怕改成了Android的标配。图就是无达标了,大家都知的。

用icon显示角标实际上是以Launcher中贯彻之,其实无论是是角标还是其它对快捷方式的增删改查,都是要Launcher支持的,应用在增删改查快捷方式和安、卸载时,都见面有相应的播音,通过这广播,Launcher会对快捷方式进行修改。

可怜庆幸,Android原生ROM的Launcher并无享让icon添加角标的职能,因为Android的计划思想是把有消息中心都放置于Notification通知栏中,只有iOS这种通知栏半残废的,才会以角标。这戏意儿,让强迫症患者,完全不能自理,每日陷落在去掉小红点的活备受。

杀悲剧,Android的AOSP代码被国内各大ROM厂商改的不能自理。很多于修改的ROM都得支撑这种角标的功用,甚至是群叔着Launcher,也供了这种意义。其基本原理也是举世一良抄,都是监听发出之播放来进行快捷方式的改,但是,关键是没有Google亲爹的支持,所有的实现还非联合,大家温馨做自己的,没有统一的接口,导致各种碎片化非常沉痛。

现行原理非常清晰了,关键就是一旦尽可能多的找到这些ROM、Launcher的改icon的广播。

在查该问题时常,我找到了https://github.com/leolin310148/ShortcutBadger
这个库房,很多地方参考了这个库房,但是该库由于那个漫长没有保安了,所以自己取了里收集之一些Badge的点子,并开了包罗万象,这里针对笔者表示感谢。

自是广告

DWCoreTextLabel自家既升级到了v1.2.3本,这个版中本人补偿加了预估尺寸的计方案与文本选择的API。废话不说,看成效吧:

哲学原理 1

DWCoreTextLabel

您觉得马上即结束了?太天真了!
旋即期有少独广告!!!
总驾驶员最近为有利于企业测试调试,以为我们程序员追踪问题,写了一个略带物,放图:

各种ROM角标分析

回头看看,距离CoreText系列首发过去一样年吗大多矣,看到第一篇稿子将超过1.3W的点击量一直车手为是压力进一步老,毕竟作为瞎逼逼杰出代表的始终车手奇迹吧要是正直一下

MIUI6&7 Badge

以下内容来自MUI开发者平台:

一如既往、基本介绍

1、默认的情景

当app 向通知栏发送了同等长达通知
(通知非带进度长长的以用户可以去除的),那么桌面app
icon角标就见面显1.此时app显示的角标数是和通栏里app发送的通知数对应之,即于通知栏发送了多少通知就见面来得小角标。

2、通知可以定义角标数

譬如说 有5查封无念邮件,通知栏里只见面显得平长条通知,但是想给角标显示5.
足以当发作通知时加个标志。

修改MIUI的原理是经过反射拿到Notification的私家属性extraNotification,但是这个extraNotification在MIUI系统中重定义了,这个仿佛就是MIUI系统中之android.app.MiuiNotification这个类似,这个类似里来个民用属性messageCount,我们而改变之messageCount值就能形的改变app
icon的角标数了。

次、实现代码

老三方app需要因此反射来调用,参考代码:

/**
 * 设置MIUI的Badge
 *
 * @param context context
 * @param count   count
 */
private static void setBadgeOfMIUI(Context context, int count) {
    Log.d("xys", "Launcher : MIUI");
    NotificationManager mNotificationManager = (NotificationManager) context
            .getSystemService(Context.NOTIFICATION_SERVICE);
    Notification.Builder builder = new Notification.Builder(context)
            .setContentTitle("title").setContentText("text").setSmallIcon(R.mipmap.ic_launcher);
    Notification notification = builder.build();
    try {
        Field field = notification.getClass().getDeclaredField("extraNotification");
        Object extraNotification = field.get(notification);
        Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
        method.invoke(extraNotification, count);
    } catch (Exception e) {
        e.printStackTrace();
    }
    mNotificationManager.notify(0, notification);
}

参考资料:

  • 关于CTFramesetterSuggestFrameSizeWithConstraints的讨论

本期并没有写Demo,毕竟代码量有接触异常,而且彼此间依赖性大,demo几乎就是是DWCoreTextLabel全部代码。

Nova Badge

Nova是千篇一律慢慢悠悠特别赞赏的Launcher,作为第三正在Launcher,它的使用率挺高(当然是在国外)。该Launcher作为业界良心,提供了content
provider供外界调用。与ZUK手机一样,良心大大的好,代码如下:

ContentValues contentValues = new ContentValues();
contentValues.put("tag", context.getPackageName() + "/" +
        AppInfoUtil.getLauncherClassName(context));
contentValues.put("count", count);
context.getContentResolver().insert(Uri.parse("content://com.teslacoilsw.notifier/unread_count"),
        contentValues);

CoreText提供的一部分函数的bug

  • CTFramesetterSuggestFrameSizeWithConstraints
    上文中涉及过这函数在传播排除区域时凡出bug的。
  • CTRunGetStringRange
    这个函数在脚下文如果当某位为不克全亮的文添加省有点模式之上,最后一个CTRun的计算range会计算错误。
  • CTLineGetOffsetForStringIndex
    这个函数同样是指向省略号模式下会错的返回0。
  • 及清除区域时,我们谈论了点滴栽消区域之方案,但是及时片种植方案还无克免一个题目,那就是是当排区域非矩形区域还和绘图区域间距小于一个字形宽度时,CoreText绘制的仿会来一些以及解除区域层。这个题材我们可透过修正排除区域之岗位要样来避免。暂勿找到完美的化解方案。

没招


Sony Badge

https://forsberg.ax/en/blog/android-notification-badge-app-icon-sony/

尺寸估算

说交尺寸估算,事实上同学等应该记得老司机于第一篇常见中涉及过CoreText提供的一个尺寸估算的函数CTFramesetterSuggestFrameSizeWithConstraints
这就是说老驾驶员又介绍一下是函数:

夫函数需要传入一下参数:

  • framesetter :
    需要进行尺寸估算的framesetter(即绘制工厂)对象,此目标就出于要绘制的富文本即可生成。
  • stringRange :
    需要参与计算尺寸的公文范围。(比如长度也200底字符串,而你独自想计算前100单字的估算尺寸来说,可以通过是参数调整)。
  • frameAttributes :
    富文本的有些外属性,这些性将会影响排版效果,这个参数稍后会细讲。
  • constraints :
    尺寸约束,就是尺寸估算的极充分境界,其用办法类似于[UIView sizeThatFits:size]
    中size的用法。
  • * fitRange :
    约束内之文本范围。及文件长度十分丰富,在约束尺寸内无法完全绘制时,fitRange会被赋值为约束内可展示的限制。

因而说通过此法,我们好像用[UIView sizeThatFits:size]以此艺术同样计算出一致段文本的预估尺寸,但是问题还尚未这样简单的到此结束:

倘想如果绘制的文书中,存在散区域来说,只能通过frameAttributes参数进行安排。

夫特性配置排除区域是者法的:

///返回排除区域字典
NSDictionary * getExclusionDic(NSArray * paths) {
    if (paths.count == 0) {
        return NULL;
    }
    NSMutableArray *pathsArray = [[NSMutableArray alloc] init];
    [paths enumerateObjectsUsingBlock:^(UIBezierPath * obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSDictionary *clippingPathDictionary = [NSDictionary dictionaryWithObject:(__bridge id)(obj.CGPath) forKey:(__bridge NSString *)kCTFramePathClippingPathAttributeName];
        [pathsArray addObject:clippingPathDictionary];
    }];
    return [NSDictionary dictionaryWithObjectsAndKeys:pathsArray,kCTFrameClippingPathsAttributeName, nil];
}

点是始终驾驶员写的归排除区域对应的frameAttributes的函数,其中paths是一个颇具想要扫除区域的路的数组(别忘了之路子需要是坐标转换后底路线)。

可是问题即使以斯排除区域及。frameAttributes可以流传一切富文本所需要的习性,但是若此传入的frameAttributes排除区域数组的确含有需要排除的区域时,计算出来的尺寸高度将会为0。而之函数如果传入的frameAttributes没有要排除的区域则计算出来的尺寸则是准确的。对于此问题出的因由,老驾驶员并没找到有关材料,只会以Stack
Overflow上来看别人领过如此一句子:

This seems to me like an iOS7 bug. I have been tinkering around, and
under iOS6, CTFramesetterSuggestFrameSizeWithConstraints returns a
size with height larger than 0. Same code under iOS7 returns a height
of 0.

—–出自关于CTFramesetterSuggestFrameSizeWithConstraints的讨论

大约的意就是是,这是iOS7下的bug,iOS6和之前是API倒是没什么问题。

为此我们今天若考虑的虽应该是,如果确有脱区域来说,我们只要怎么算预估尺寸呢?

直驾驶员的想法是赢得每个CTLine的尺寸后,取并集即为富有CTLine所需尺寸。然后再次对具备排除区域之尺寸取并集,即为绘制区域之尺码

上述就是老驾驶员对有清除区域的预估尺寸的笔触,以下则是代码(这个没特意写demo,截取自老司机的DWCoreTextLabel中对-sizeThatFits:方法的重写实现):

-(CGSize)sizeThatFits:(CGSize)size {
    ///计算绘制尺寸限制
    CGFloat limitWidth = (size.width - self.textInsets.left - self.textInsets.right) > 0 ? (size.width - self.textInsets.left - self.textInsets.right) : 0;
    CGFloat limitHeight = (size.height - self.textInsets.top - self.textInsets.bottom) > 0 ? (size.height - self.textInsets.top - self.textInsets.bottom) : 0;

    ///获取排除区域(考虑偏移矫正,保证正确绘制)
    NSArray * exclusionPaths = [self handleExclusionPathsWithOffset:self.textInsets.bottom - self.textInsets.top];
    CGRect frame = CGRectMake(self.textInsets.left, self.textInsets.bottom, limitWidth, limitHeight);
    NSDictionary * exclusionConfig = getExclusionDic(exclusionPaths, frame);
    BOOL needDrawString = self.attributedText.length || self.text.length;

    NSMutableAttributedString * mAStr = nil;
    if (needDrawString) {
        ///获取要绘制的文本(初步处理,未处理插入图片、句尾省略号、高亮)
        mAStr = getMAStr(self,limitWidth,exclusionPaths);
    }
    CTFramesetterRef frameSetter4Cal = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mAStr);
    CTFrameRef frame4Cal = CTFramesetterCreateFrame(frameSetter4Cal, CFRangeMake(0, 0), [UIBezierPath bezierPathWithRect:frame].CGPath, (__bridge_retained CFDictionaryRef)exclusionConfig);

    CFRange visibleRange = getRangeToDrawForVisibleString(frame4Cal);

    ///处理插入图片
    if (needDrawString) {
        NSMutableArray * arrInsert = self.insertImageArr.copy;
        if (arrInsert.count) {
            ///富文本插入图片占位符
            [self handleStr:mAStr withInsertImageArr:arrInsert arrLocationImgHasAdd:[NSMutableArray array]];
            ///插入图片后重新处理工厂及frame,添加插入图片后的字符串,消除插入图片影响
            CFSAFERELEASE(frameSetter4Cal)
            CFSAFERELEASE(frame4Cal)
            frameSetter4Cal = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mAStr);
            frame4Cal = CTFramesetterCreateFrame(frameSetter4Cal, CFRangeMake(0, 0), [UIBezierPath bezierPathWithRect:frame].CGPath, (__bridge_retained CFDictionaryRef)exclusionConfig);
            visibleRange = getRangeToDrawForVisibleString(frame4Cal);
        }
    }

    if (exclusionPaths.count == 0) {///如果没有排除区域则使用系统计算函数
        CGSize restrictSize = CGSizeMake(limitWidth, MAXFLOAT);
        if (self.numberOfLines == 1) {
            restrictSize = CGSizeMake(MAXFLOAT, MAXFLOAT);
        }
        CGSize suggestSize = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter4Cal, visibleRange, nil, restrictSize, nil);
        CFSAFERELEASE(frameSetter4Cal);
        CFSAFERELEASE(frame4Cal);
        return CGSizeMake(suggestSize.width + self.textInsets.left + self.textInsets.right, suggestSize.height + self.textInsets.top + self.textInsets.bottom);
    }

    ///计算drawFrame及drawPath
    UIBezierPath * drawP = [self handleDrawFrameAndPathWithLimitWidth:limitWidth limitHeight:limitHeight frameSetter:frameSetter4Cal rangeToDraw:visibleRange exclusionPaths:exclusionPaths];

    CFSAFERELEASE(frameSetter4Cal)
    CFSAFERELEASE(frame4Cal)

    ///绘制的工厂
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)mAStr);
    ///绘制范围为可见范围加1,防止末尾省略号失效(由于path为可见尺寸,故仅绘制可见范围时有的时候末尾的省略号会失效,同时不可超过字符串本身长度)
    CFRange drawRange = CFRangeMake(0, visibleRange.length < mAStr.length ? visibleRange.length + 1 : mAStr.length);
    CTFrameRef visibleFrame = CTFramesetterCreateFrame(frameSetter, drawRange, drawP.CGPath, (__bridge_retained CFDictionaryRef)exclusionConfig);

    __block CGRect desFrame = CGRectZero;

    DWCoreTextLayout * layout = [DWCoreTextLayout layoutWithCTFrame:visibleFrame convertHeight:size.height considerGlyphs:NO];

    [layout.lines enumerateObjectsUsingBlock:^(DWCTLineWrapper * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        CGRect temp = obj.frame;
        desFrame = CGRectUnion(temp, desFrame);
    }];

    CFSAFERELEASE(frameSetter)
    CFSAFERELEASE(visibleFrame)

    desFrame = CGRectMake(0, 0, ceil(desFrame.origin.x + desFrame.size.width + self.textInsets.right), ceil(desFrame.origin.y + desFrame.size.height + self.textInsets.bottom));

    ///重新获取为矫正偏移的图片实际绘制Path
    exclusionPaths = [self handleExclusionPathsWithOffset:0];
    [exclusionPaths enumerateObjectsUsingBlock:^(UIBezierPath * obj, NSUInteger idx, BOOL * _Nonnull stop) {
        desFrame = CGRectUnion(obj.bounds, desFrame);
    }];

    CGRect limitRect = CGRectMake(0, 0, size.width, size.height);
    desFrame = CGRectIntersection(limitRect, desFrame);
    return desFrame.size;
}

术被恐怕小措施是直车手的工具方法,其实还不紧要,只要看注释就足以了。想明白每个方法的求实实现,你或待去他的出处去看看DWCoreTextLabel。

顺带一提的凡,老驾驶员于寻觅这CTFramesetterSuggestFrameSizeWithConstraints函数的时段刚好对脱区域绘制时的贯彻有了初的笔触。第三篇稿子被,老驾驶员介绍的凡,在盘算起之绘制区域drawPath中直接拼接上需要排除的区域的路径,那么根据奇偶原则自然就免去了所挑选区域。而这次老车手的初思路则是,在转CTFrame的部CTFramesetterCreateFrame受到做小动作哲学原理。此函数也闹frameAttributes这个参数,传入上文中提到的排除区域字典的言语也可是及消除区域的功效。

但这简单单实现方式在功能达到还有一些小区别:

drawPath拼接的思路被,如果个别单破区域有交集,根据奇偶原则,交集则会让认为是非排除区域。而frameAttributes传入配置字典这种办法中,则交集仍为破除区域。

少数种植方案效果相比

根据这个特性结合镇司机的DWCoreTextLabel中的有关需求,老车手选择了更为恰当的老二种思路并在DWCoreTextLabel中召开了有关修改。不过这有限种植思路并无高低之分,还是要因具体的要求来选。


ZUK ZUI Badge

ZUK作为一个异常小众的无绳电话机厂商,居然以网上官方给来了详细的开发者文档,就随即或多或少,很多分外厂都欠优秀打打自己之耳光。

由实在找不交ZUK的测试机,所以这边给出ZUK的开发者文档,有得之团结省吧:

http://developer.zuk.com/detail/12

文山会海文章:

华为EMUI Badge

此时此刻华为的ROM只支持于放的App添加角标,华为本身并未受出相应的接口。

DWLogger仓库

哲学原理 2

DWLogger

旋即是一个日记助手类,他得辅助而当App中一直翻输出的日记,同时不影响计算机端的日志输出。

重复多状况下他可以为您以非连接电脑的情下同样可以查阅输出的日记,这将会见救你的测试妹妹,发生问题外啊闹矣一定查看问题的法子。同时他拿机关备份日志至磁盘,以救助你分析数据的下下,当然,他呢得以活动采集崩溃日志,当测试妹妹崩溃后,你可以一直翻日志与截图而无是苦逼的夺复现。他尚好拉而吗日志划分等级,以方便你分等级查看日志,同时你吧足以利用搜索功能来探寻特定日志。

喜的讲话,给我个Star吧~

HTC Badge

HTC虽然没落了,但好歹是第一不过Android的寄生兽,好歹也支持下。

Intent intentNotification = new Intent("com.htc.launcher.action.SET_NOTIFICATION");
ComponentName localComponentName = new ComponentName(context.getPackageName(),
        AppInfoUtil.getLauncherClassName(context));
intentNotification.putExtra("com.htc.launcher.extra.COMPONENT", localComponentName.flattenToShortString());
intentNotification.putExtra("com.htc.launcher.extra.COUNT", count);
context.sendBroadcast(intentNotification);

Intent intentShortcut = new Intent("com.htc.launcher.action.UPDATE_SHORTCUT");
intentShortcut.putExtra("packagename", context.getPackageName());
intentShortcut.putExtra("count", count);
context.sendBroadcast(intentShortcut);

夫规律同是动广播,不讲了。

CoreText实现图文混排之尺寸估算及文件选择

酷派 Badge

大概粗暴,不支持。我爱,类原生。

部分妙不可言的

当知晓了部分ROM的转角标的法则,我们好开一些幽默的东西。前面在说LG三星Sony的ROM的时光,已经关系了,广播就待后人包名和启动Activity名就是好给自由一个icon添加角标,因此。。。直接看代码吧:

/**
 * Bug利用测试,请勿滥用
 *
 * @param view view
 */
public void madMode(View view) {
    madMode(99);
}

/**
 * 清除Bug角标
 *
 * @param view view
 */
public void cleanMadMode(View view) {
    madMode(0);
}

/**
 * 获取所有App的包名和启动类名
 *
 * @param count count
 */
private void madMode(int count) {
    Intent intent = new Intent(Intent.ACTION_MAIN, null);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    List<ResolveInfo> list = getPackageManager().queryIntentActivities(
            intent, PackageManager.GET_ACTIVITIES);
    for (int i = 0; i < list.size(); i++) {
        ActivityInfo activityInfo = list.get(i).activityInfo;
        String activityName = activityInfo.name;
        String packageName = activityInfo.applicationInfo.packageName;
        BadgeUtil.setBadgeOfMadMode(getApplicationContext(), count, packageName, activityName);
    }
}

非常简单的代码,就是经过PM找有具有启动Intent的Activity,再取出其包名,通过安装来上加角标。效果使图:

device-2015-12-07-141255.png

device-2015-12-07-141314.png

device-2015-12-07-141337.png

OK,丧心病狂,逼死强迫症处女座。

告无滥用,由此引起的全套问题,不要找我

吁不要提桌面背景!!!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图