[6.8.0]冷启动三期主页状态条
@@ -63,7 +63,7 @@ object ColdStartManager: IMoGoAutopilotStatusListener, IDataCenterBizListener {
|
||||
//已登录且距离上次冷启动成功超过1分钟,再次展示冷启动页面
|
||||
if(!ColdStartConfig.getShowWindowStatus() && loginStatus && System.currentTimeMillis().minus(ColdStartConfig.getColdStartSuccessTime())>60000){
|
||||
if(System.currentTimeMillis().minus(ipcConnectedTime) > 60000){
|
||||
CallerHmiManager.showColdStartWindow()
|
||||
CallerHmiManager.showColdStartProcessView()
|
||||
}
|
||||
}
|
||||
}else{
|
||||
|
||||
@@ -646,4 +646,11 @@ class MoGoHmiProvider : IMoGoHmiProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示冷启动进度条
|
||||
*/
|
||||
override fun showColdStartProcessView() {
|
||||
CallerHmiViewControlListenerManager.invokeColdStartProcessView()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
package com.mogo.eagle.core.function.hmi.ui.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.TransitionDrawable
|
||||
import android.os.CountDownTimer
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoColdStartStateListener
|
||||
import com.mogo.eagle.core.function.api.hmi.view.IViewControlListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerColdStartStateListenerManager
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiViewControlListenerManager
|
||||
import com.mogo.eagle.core.function.hmi.R
|
||||
import com.mogo.eagle.core.function.hmi.util.FrameAnimatorContainerUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.zhjt.mogo.adas.data.AdasConstants
|
||||
import com.zhjt.mogo_core_function_devatools.coldstart.ColdStartConfig
|
||||
import kotlinx.android.synthetic.main.view_cold_start_process.view.ivColdStartProcess
|
||||
import system_master.SsmInfo
|
||||
import system_master.SystemStatusInfo
|
||||
import java.util.Locale
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
/**
|
||||
* 冷启动三期
|
||||
* 冷启动进度条,点击后会打开冷启动详情页面
|
||||
*/
|
||||
class ColdStartProcessView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr),IViewControlListener,
|
||||
IMoGoAutopilotStatusListener, IMoGoColdStartStateListener {
|
||||
|
||||
companion object {
|
||||
const val TAG = "ColdStartProcessView"
|
||||
const val LOAD_SSM_WAITING_TIME = 180000L //SSM加载超时等待时间
|
||||
const val COLD_START_WAITING_TIME = 600000L //冷启动超时等待时间
|
||||
}
|
||||
|
||||
private var ipcConnectStatus = false //连接域控状态,默认是未连接
|
||||
private var ssmConnectStatus = false //SSM连接状态,默认是未连接
|
||||
private var coldStartStatus = false //冷启动状态,默认是未冷启动成功
|
||||
|
||||
private var currentColdStartSuccess = false //冷启动成功状态,也是成功后动画完成状态
|
||||
|
||||
private var connectSSMTimer: CountDownTimer?= null //连接SSM等待倒计时
|
||||
private var connectColdStartTimer: CountDownTimer?= null //连接冷启动等待倒计时
|
||||
|
||||
private var newColdStart: Boolean = false //SSM是否支持新版冷启动
|
||||
|
||||
|
||||
private var coldStartProcessNormalAnim: FrameAnimatorContainerUtils ?= null
|
||||
private var coldStartProcessAbnormalAnim: FrameAnimatorContainerUtils ?= null
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context).inflate(R.layout.view_cold_start_process, this, true)
|
||||
initView()
|
||||
}
|
||||
|
||||
private fun initView(){
|
||||
coldStartProcessNormalAnim = FrameAnimatorContainerUtils(R.array.cold_start_process_normal,40,ivColdStartProcess)
|
||||
coldStartProcessAbnormalAnim = FrameAnimatorContainerUtils(R.array.cold_start_process_abnormal,40,ivColdStartProcess)
|
||||
|
||||
|
||||
val transition = TransitionDrawable(
|
||||
arrayOf(
|
||||
ContextCompat.getDrawable(context, R.drawable.icon_cold_start_success_01), // 当前图片
|
||||
ContextCompat.getDrawable(context, R.drawable.icon_cold_start_success_02) // 要渐变到的图片
|
||||
)
|
||||
)
|
||||
ivColdStartProcess.setImageDrawable(transition)
|
||||
transition.isCrossFadeEnabled = true
|
||||
var tag = true
|
||||
val testTimer = object: CountDownTimer(30000,500){
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
ThreadUtils.runOnUiThread {
|
||||
tag = if(tag){
|
||||
transition.startTransition(500)
|
||||
false
|
||||
}else{
|
||||
transition.reverseTransition(500)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
ThreadUtils.runOnUiThread {
|
||||
this@ColdStartProcessView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ivColdStartProcess.setOnClickListener {
|
||||
testTimer.start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
CallerHmiViewControlListenerManager.addListener(TAG,this)
|
||||
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
|
||||
CallerColdStartStateListenerManager.addListener(TAG,this)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
CallerHmiViewControlListenerManager.removeListener(TAG)
|
||||
CallerAutoPilotStatusListenerManager.removeListener(TAG)
|
||||
CallerColdStartStateListenerManager.removeListener(TAG)
|
||||
coldStartProcessNormalAnim?.release()
|
||||
coldStartProcessAbnormalAnim?.release()
|
||||
}
|
||||
|
||||
override fun showColdStartProcessView() {
|
||||
super.showColdStartProcessView()
|
||||
if(this.visibility != View.VISIBLE){
|
||||
this.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 域控连接状态
|
||||
*/
|
||||
override fun onAutopilotIpcConnectStatusChanged(
|
||||
status: AdasConstants.IpcConnectionStatus,
|
||||
reason: String?
|
||||
) {
|
||||
if(status == AdasConstants.IpcConnectionStatus.CONNECTED){
|
||||
//域控连接成功
|
||||
if(coldStartProcessAbnormalAnim?.isPlaying() == true){
|
||||
coldStartProcessAbnormalAnim?.stop()
|
||||
}
|
||||
coldStartProcessNormalAnim?.start()
|
||||
|
||||
}else{
|
||||
//域控连接失败
|
||||
if(coldStartProcessNormalAnim?.isPlaying() == true){
|
||||
coldStartProcessNormalAnim?.stop()
|
||||
}
|
||||
coldStartProcessAbnormalAnim?.start()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态查询应答
|
||||
* @param status 数据
|
||||
* HQ、M1 MAP350开始弃用,其他车型MAP360开始弃用
|
||||
*/
|
||||
override fun onAutopilotStatusRespByQuery(status: SystemStatusInfo.StatusInfo){
|
||||
ThreadUtils.runOnUiThread{
|
||||
//SSM连接成功
|
||||
connectSSMSuccess()
|
||||
//通过autoPilotReady判断冷启动是否成功
|
||||
if(status.hasAutoPilotReady() && status.autoPilotReady && !coldStartStatus){
|
||||
coldStartStatus = true
|
||||
showColdStartSuccessView()
|
||||
//记录冷启动成功时间
|
||||
ColdStartConfig.setColdStartSuccessTime(System.currentTimeMillis())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定频SSM接口
|
||||
* 1hz hq m1 MAP350开始支持,其他车型MAP360开始支持
|
||||
* 定频SSM接入后 onStatusQueryResp 状态查询应答接口将弃用
|
||||
* @param statusInf 数据
|
||||
*/
|
||||
override fun onSystemStatus(statusInf: SsmInfo.SsmStatusInf){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 冷启动状态
|
||||
*/
|
||||
override fun onColdStartState(
|
||||
token: Long,
|
||||
timestamp: Long,
|
||||
isQuery: Boolean,
|
||||
coldStartState: SsmInfo.ColdStartState?
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
private fun connectSSMSuccess(){
|
||||
|
||||
}
|
||||
|
||||
private fun showColdStartSuccessView(){
|
||||
|
||||
}
|
||||
|
||||
private val pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+")
|
||||
|
||||
/**
|
||||
* 解析版本 格式 xxx.xxx.xxx(x的数量不固定)
|
||||
* 仅用于版本比较,不能用于展示
|
||||
* 例如:
|
||||
* "12.03.04" 解析结果:120304
|
||||
* "2.11.0" 解析结果:21100
|
||||
* "3.0.0" 解析结果:30000
|
||||
* 目前已用于DockerVersion和MaserVersion的解析
|
||||
*
|
||||
* @param isUseAll 是否使用全部截取数据 true:表示 12.34.56 截取之后 123456 false:表示12.34.56 截取之后 12
|
||||
* @param ver 版本字符串 例如:"MAP-taxi_RoboTaxi_df_2.8.0.3_20220928_test" 解析结果为:280
|
||||
* @return -1表示解析失败
|
||||
*/
|
||||
private fun parseVersion(isUseAll: Boolean, ver: String): Int {
|
||||
var version = -1
|
||||
if (!TextUtils.isEmpty(ver)) {
|
||||
try {
|
||||
val matcher: Matcher = pattern.matcher(ver)
|
||||
if (matcher.find()) {
|
||||
var group = matcher.group()
|
||||
if (!TextUtils.isEmpty(group)) {
|
||||
val format = "%02d"
|
||||
if (isUseAll) {
|
||||
val temp = group.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()
|
||||
group = String.format(Locale.getDefault(), format, temp[0].toInt())
|
||||
group += String.format(Locale.getDefault(), format, temp[1].toInt())
|
||||
group += String.format(Locale.getDefault(), format, temp[2].toInt())
|
||||
} else {
|
||||
group = group.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()[0]
|
||||
}
|
||||
version = group.toInt()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "版本解析失败=$ver", e)
|
||||
}
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
package com.mogo.eagle.core.function.hmi.util
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.widget.ImageView
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadPoolManagerUtils
|
||||
import java.lang.ref.SoftReference
|
||||
import java.util.concurrent.ArrayBlockingQueue
|
||||
import java.util.concurrent.Future
|
||||
|
||||
class FrameAnimatorContainerUtils (resId: Int,
|
||||
fps: Int,
|
||||
imageView: ImageView,
|
||||
isOnce: Boolean = false,// 一次性的 true 值播放一次 false 重复播放
|
||||
initFirstFrame:Boolean = true,
|
||||
width:Int = -1,
|
||||
height:Int = -1){
|
||||
private val TAG = "FrameAnimatorContainerUtils"
|
||||
private lateinit var mFrames: IntArray // 帧数组
|
||||
private var mIndex = 0 // 当前帧
|
||||
private var mShouldRun = false // 开始/停止播放用
|
||||
private var mIsRunning = false // 动画是否正在播放,防止重复播放
|
||||
private var mSoftReferenceImageView: SoftReference<ImageView>? = null // 软引用ImageView,以便及时释放掉
|
||||
private var mHandler: Handler? = null
|
||||
private var mDelayMillis = 0
|
||||
var mOnAnimationStoppedListener: OnAnimationStoppedListener? = null//播放停止监听
|
||||
var isOnce:Boolean = false
|
||||
|
||||
private val readQueue = ArrayBlockingQueue<Pair<Bitmap,BitmapFactory.Options>>(8,true)
|
||||
private val writeQueue = ArrayBlockingQueue<Pair<Bitmap,BitmapFactory.Options>>(8,true)
|
||||
|
||||
private var currentPoll:Pair<Bitmap,BitmapFactory.Options>?=null
|
||||
|
||||
private var decodeImage: Future<*>?=null
|
||||
|
||||
|
||||
init {
|
||||
createAnimation(imageView, getData(resId), fps,initFirstFrame,width,height)
|
||||
this.isOnce = isOnce
|
||||
}
|
||||
|
||||
private fun createAnimation(
|
||||
imageView: ImageView,
|
||||
frames: IntArray,
|
||||
fps: Int,
|
||||
initFirstFrame: Boolean,
|
||||
width: Int,
|
||||
height: Int
|
||||
) {
|
||||
mHandler = object: Handler(Looper.myLooper()!!){
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
if(msg.what==0){
|
||||
val imageView = mSoftReferenceImageView!!.get()
|
||||
if (!mShouldRun || imageView == null) {
|
||||
mIsRunning = false
|
||||
if (mOnAnimationStoppedListener != null) {
|
||||
mOnAnimationStoppedListener!!.AnimationStopped()
|
||||
}
|
||||
return
|
||||
}
|
||||
mIsRunning = true
|
||||
//新开线程去读下一帧
|
||||
if (imageView.isShown) {
|
||||
if (!mShouldRun) {
|
||||
mIsRunning = false
|
||||
CallerLogger.d(TAG,"暂停播放")
|
||||
if (mOnAnimationStoppedListener != null) {
|
||||
mOnAnimationStoppedListener!!.AnimationStopped()
|
||||
}
|
||||
return
|
||||
}
|
||||
mHandler?.sendEmptyMessageDelayed(0,mDelayMillis.toLong())
|
||||
if(currentPoll!=null){
|
||||
writeQueue.offer(currentPoll)
|
||||
currentPoll = null
|
||||
}
|
||||
currentPoll = readQueue.poll()
|
||||
if(currentPoll!=null){
|
||||
val bitmap = currentPoll!!.first
|
||||
imageView.setImageBitmap(bitmap)
|
||||
}else{
|
||||
CallerLogger.d(TAG,"加载过慢了")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mFrames = frames
|
||||
mIndex = -1
|
||||
mSoftReferenceImageView = SoftReference(imageView)
|
||||
mShouldRun = false
|
||||
mIsRunning = false
|
||||
mDelayMillis = 1000 / fps //帧动画时间间隔,毫秒
|
||||
CallerLogger.d(TAG,"两帧时间:${mDelayMillis}")
|
||||
if(initFirstFrame) {
|
||||
imageView.setImageResource(mFrames[0])
|
||||
}
|
||||
var widthImage = -1
|
||||
var heightImage = -1
|
||||
var config = Bitmap.Config.ARGB_8888
|
||||
if(width>0&&height>0){
|
||||
widthImage = width
|
||||
heightImage = height
|
||||
}else{
|
||||
try {
|
||||
val bmp = (imageView.drawable as BitmapDrawable).bitmap
|
||||
widthImage = bmp.width
|
||||
heightImage = bmp.height
|
||||
config = bmp.config
|
||||
}catch (e:Exception){
|
||||
throw RuntimeException("请设置图片或传递大小")
|
||||
}
|
||||
}
|
||||
// 当图片大小类型相同时进行复用,避免频繁GC
|
||||
|
||||
for (i in 0..7) {
|
||||
val mBitmap = Bitmap.createBitmap(widthImage, heightImage, config)
|
||||
val mBitmapOptions = BitmapFactory.Options()
|
||||
//设置Bitmap内存复用
|
||||
mBitmapOptions.inBitmap = mBitmap //Bitmap复用内存块,类似对象池,避免不必要的内存分配和回收
|
||||
mBitmapOptions.inMutable = true //解码时返回可变Bitmap
|
||||
mBitmapOptions.inSampleSize = 1 //缩放比例
|
||||
writeQueue.add(Pair(mBitmap,mBitmapOptions))
|
||||
}
|
||||
|
||||
decodeImage = ThreadPoolManagerUtils.getsInstance().submit(object: Runnable{
|
||||
override fun run() {
|
||||
while (true) {
|
||||
val (bitmap1, options) = writeQueue.take()
|
||||
mIndex++
|
||||
if (mIndex >= mFrames.size){
|
||||
mIndex = 0
|
||||
if(isOnce){
|
||||
stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
val index: Int = mIndex
|
||||
val imageRes: Int = mFrames[index]
|
||||
var bitmap: Bitmap? = null
|
||||
try {
|
||||
bitmap = BitmapFactory.decodeResource(
|
||||
imageView.resources,
|
||||
imageRes,
|
||||
options
|
||||
)
|
||||
options.inBitmap = bitmap
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (bitmap != null) {
|
||||
readQueue.put(Pair(bitmap, options))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//循环读取下一帧
|
||||
private val next: Int
|
||||
get() {
|
||||
mIndex++
|
||||
if (mIndex >= mFrames.size){
|
||||
mIndex = 0
|
||||
}
|
||||
return mIndex
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun reStart(){
|
||||
resetQueue()
|
||||
mIndex = 0
|
||||
mIsRunning = false
|
||||
start()
|
||||
}
|
||||
|
||||
private fun resetQueue(){
|
||||
val temp = mutableListOf<Pair<Bitmap, BitmapFactory.Options>>()
|
||||
|
||||
val writeIterator = writeQueue.iterator()
|
||||
while (writeIterator.hasNext()) {
|
||||
temp.add(writeIterator.next())
|
||||
}
|
||||
|
||||
val readIterator = readQueue.iterator()
|
||||
while (readIterator.hasNext()) {
|
||||
temp.add(readIterator.next())
|
||||
}
|
||||
for (pair in temp) {
|
||||
writeQueue.add(pair)
|
||||
}
|
||||
}
|
||||
|
||||
fun release(){
|
||||
mShouldRun = false
|
||||
decodeImage?.cancel(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放动画,同步锁防止多线程读帧时,数据安全问题
|
||||
*/
|
||||
@Synchronized
|
||||
fun start() {
|
||||
mShouldRun = true
|
||||
if (mIsRunning) return
|
||||
mHandler?.removeCallbacksAndMessages(null)
|
||||
mHandler?.sendEmptyMessage(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放
|
||||
*/
|
||||
@Synchronized
|
||||
fun stop() {
|
||||
mShouldRun = false
|
||||
}
|
||||
|
||||
fun isPlaying():Boolean{
|
||||
return mShouldRun
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置停止播放监听
|
||||
* @param listener 设置监听
|
||||
*/
|
||||
fun setOnAnimStopListener(listener: OnAnimationStoppedListener?) {
|
||||
mOnAnimationStoppedListener = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* 从xml中读取帧数组
|
||||
* @param resId
|
||||
* @return
|
||||
*/
|
||||
fun getData(resId: Int): IntArray {
|
||||
val array = AbsMogoApplication.getApp().resources.obtainTypedArray(resId)
|
||||
val len = array.length()
|
||||
val intArray = IntArray(array.length())
|
||||
for (i in 0 until len) {
|
||||
intArray[i] = array.getResourceId(i, 0)
|
||||
}
|
||||
array.recycle()
|
||||
return intArray
|
||||
}
|
||||
|
||||
fun setData(mFrames: IntArray){
|
||||
this.mFrames = mFrames
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放监听
|
||||
*/
|
||||
interface OnAnimationStoppedListener {
|
||||
fun AnimationStopped()
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |