亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android DownloadProvider 源碼詳解

 更新時(shí)間:2016年11月11日 15:12:34   作者:極度寒冰  
這篇文章主要介紹了Android DownloadProvider 源碼詳解的相關(guān)資料,需要的朋友可以參考下

Android DownloadProvider 源碼分析:

Download的源碼編譯分為兩個(gè)部分,一個(gè)是DownloadProvider.apk, 一個(gè)是DownloadProviderUi.apk.

這兩個(gè)apk的源碼分別位于

packages/providers/DownloadProvider/ui/src
packages/providers/DownloadProvider/src

其中,DownloadProvider的部分是下載邏輯的實(shí)現(xiàn),而DownloadProviderUi是界面部分的實(shí)現(xiàn)。

然后DownloadProvider里面的下載雖然主要是通過(guò)DownloadService進(jìn)行的操作,但是由于涉及到Notification的更新,下載進(jìn)度的展示,下載的管理等。

所以還是有不少其它的類(lèi)來(lái)分別進(jìn)行操作。

DownloadProvider --  數(shù)據(jù)庫(kù)操作的封裝,繼承自ContentProvider;
DownloadManager -- 大部分邏輯是進(jìn)一步封裝數(shù)據(jù)操作,供外部調(diào)用;
DownloadService -- 封裝文件download,delete等操作,并且操縱下載的norification;繼承自Service;
DownloadNotifier -- 狀態(tài)欄Notification邏輯;
DownloadReceiver -- 配合DownloadNotifier進(jìn)行文件的操作及其N(xiāo)otification;
DownloadList -- Download app主界面,文件界面交互;

下載一般是從Browser里面點(diǎn)擊鏈接開(kāi)始,我們先來(lái)看一下Browser中的代碼

在browser的src/com/Android/browser/DownloadHandler.Java函數(shù)中,我們可以看到一個(gè)很完整的Download的調(diào)用,我們?cè)趯?xiě)自己的app的時(shí)候,也可以對(duì)這一段進(jìn)行參考:

public static void startingDownload(Activity activity, 
    String url, String userAgent, String contentDisposition, 
    String mimetype, String referer, boolean privateBrowsing, long contentLength, 
    String filename, String downloadPath) { 
  // java.net.URI is a lot stricter than KURL so we have to encode some 
  // extra characters. Fix for b 2538060 and b 1634719 
  WebAddress webAddress; 
  try { 
    webAddress = new WebAddress(url); 
    webAddress.setPath(encodePath(webAddress.getPath())); 
  } catch (Exception e) { 
    // This only happens for very bad urls, we want to chatch the 
    // exception here 
    Log.e(LOGTAG, "Exception trying to parse url:" + url); 
    return; 
  } 
 
  String addressString = webAddress.toString(); 
  Uri uri = Uri.parse(addressString); 
  final DownloadManager.Request request; 
  try { 
    request = new DownloadManager.Request(uri); 
  } catch (IllegalArgumentException e) { 
    Toast.makeText(activity, R.string.cannot_download, Toast.LENGTH_SHORT).show(); 
    return; 
  } 
  request.setMimeType(mimetype); 
  // set downloaded file destination to /sdcard/Download. 
  // or, should it be set to one of several Environment.DIRECTORY* dirs 
  // depending on mimetype? 
  try { 
    setDestinationDir(downloadPath, filename, request); 
  } catch (Exception e) { 
    showNoEnoughMemoryDialog(activity); 
    return; 
  } 
  // let this downloaded file be scanned by MediaScanner - so that it can 
  // show up in Gallery app, for example. 
  request.allowScanningByMediaScanner(); 
  request.setDescription(webAddress.getHost()); 
  // XXX: Have to use the old url since the cookies were stored using the 
  // old percent-encoded url. 
  String cookies = CookieManager.getInstance().getCookie(url, privateBrowsing); 
  request.addRequestHeader("cookie", cookies); 
  request.addRequestHeader("User-Agent", userAgent); 
  request.addRequestHeader("Referer", referer); 
  request.setNotificationVisibility( 
      DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 
  final DownloadManager manager = (DownloadManager) activity 
      .getSystemService(Context.DOWNLOAD_SERVICE); 
  new Thread("Browser download") { 
    public void run() { 
      manager.enqueue(request); 
    } 
  }.start(); 
  showStartDownloadToast(activity); 
} 

在這個(gè)操作中,我們看到添加了request的各種參數(shù),然后最后調(diào)用了DownloadManager的enqueue進(jìn)行下載,并且在開(kāi)始后,彈出了開(kāi)始下載的這個(gè)toast。manager是一個(gè)DownloadManager的實(shí)例,DownloadManager是存在與frameworks/base/core/java/android/app/DownloadManager.java??梢钥吹絜nqueue的實(shí)現(xiàn)為:

public long enqueue(Request request) { 
  ContentValues values = request.toContentValues(mPackageName); 
  Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values); 
  long id = Long.parseLong(downloadUri.getLastPathSegment()); 
  return id; 

enqueue函數(shù)主要是將Rquest實(shí)例分解組成一個(gè)ContentValues實(shí)例,并且添加到數(shù)據(jù)庫(kù)中,函數(shù)返回插入的這條數(shù)據(jù)返回的ID;ContentResolver.insert函數(shù)會(huì)調(diào)用到DownloadProvider實(shí)現(xiàn)的ContentProvider的insert函數(shù)中去,如果我們?nèi)ゲ榭磇nsert的code的話(huà),我們可以看到操作是很多的。但是我們只需要關(guān)注幾個(gè)關(guān)鍵的部分:

...... 
//將相關(guān)的請(qǐng)求參數(shù),配置等插入到downloads數(shù)據(jù)庫(kù); 
long rowID = db.insert(DB_TABLE, null, filteredValues); 
...... 
//將相關(guān)的請(qǐng)求參數(shù),配置等插入到request_headers數(shù)據(jù)庫(kù)中; 
insertRequestHeaders(db, rowID, values); 
...... 
if (values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION) == 
        Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) { 
      // When notification is requested, kick off service to process all 
      // relevant downloads. 
//啟動(dòng)DownloadService進(jìn)行下載及其它工作 
      if (Downloads.Impl.isNotificationToBeDisplayed(vis)) { 
        context.startService(new Intent(context, DownloadService.class)); 
      } 
    } else { 
      context.startService(new Intent(context, DownloadService.class)); 
    } 
    notifyContentChanged(uri, match); 
    return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID); 

在這邊,我們就可以看到下載的DownloadService的調(diào)用了。因?yàn)槭且粋€(gè)startService的方法,所以我們?cè)贒ownloadService里面,是要去走oncreate的方法的。

@Override 
public void onCreate() { 
  super.onCreate(); 
  if (Constants.LOGVV) { 
    Log.v(Constants.TAG, "Service onCreate"); 
  } 
 
  if (mSystemFacade == null) { 
    mSystemFacade = new RealSystemFacade(this); 
  } 
 
  mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 
  mStorageManager = new StorageManager(this); 
 
  mUpdateThread = new HandlerThread(TAG + "-UpdateThread"); 
  mUpdateThread.start(); 
  mUpdateHandler = new Handler(mUpdateThread.getLooper(), mUpdateCallback); 
  mScanner = new DownloadScanner(this); 
  mNotifier = new DownloadNotifier(this); 
  mNotifier.cancelAll(); 
 
  mObserver = new DownloadManagerContentObserver(); 
  getContentResolver().registerContentObserver(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 
      true, mObserver); 
} 

這邊的話(huà),我們可以看到先去啟動(dòng)了一個(gè)handler去接收callback的處理

mUpdateThread = new HandlerThread(TAG + "-UpdateThread"); 
 mUpdateThread.start(); 
 mUpdateHandler = new Handler(mUpdateThread.getLooper(), mUpdateCallback); 

然后去

getContentResolver().registerContentObserver(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 
        true, mObserver) 

是去注冊(cè)監(jiān)聽(tīng)Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI的Observer。
而oncreate之后,就會(huì)去調(diào)用onStartCommand方法.

@Override 
ublic int onStartCommand(Intent intent, int flags, int startId) { 
  int returnValue = super.onStartCommand(intent, flags, startId); 
  if (Constants.LOGVV) { 
    Log.v(Constants.TAG, "Service onStart"); 
  } 
  mLastStartId = startId; 
  enqueueUpdate(); 
  return returnValue; 
} 

在enqueueUpdate的函數(shù)中,我們會(huì)向mUpdateHandler發(fā)送一個(gè)MSG_UPDATE Message,

private void enqueueUpdate() { 
  mUpdateHandler.removeMessages(MSG_UPDATE); 
  mUpdateHandler.obtainMessage(MSG_UPDATE, mLastStartId, -1).sendToTarget(); 
} 

mUpdateCallback中接收到并且處理:

private Handler.Callback mUpdateCallback = new Handler.Callback() { 
    @Override 
    public boolean handleMessage(Message msg) { 
      Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
      final int startId = msg.arg1; 
      final boolean isActive; 
      synchronized (mDownloads) { 
        isActive = updateLocked(); 
      } 
      ...... 
      if (isActive) { 
//如果Active,則會(huì)在Delayed 5×60000ms后發(fā)送MSG_FINAL_UPDATE Message,主要是為了“any finished operations that didn't trigger an update pass.” 
        enqueueFinalUpdate(); 
      } else { 
//如果沒(méi)有Active的任務(wù)正在進(jìn)行,就會(huì)停止Service以及其它 
        if (stopSelfResult(startId)) { 
          if (DEBUG_LIFECYCLE) Log.v(TAG, "Nothing left; stopped"); 
          getContentResolver().unregisterContentObserver(mObserver); 
          mScanner.shutdown(); 
          mUpdateThread.quit(); 
        } 
      } 
      return true; 
    } 
  }; 

這邊的重點(diǎn)是updateLocked()函數(shù)


  private boolean updateLocked() { 
    final long now = mSystemFacade.currentTimeMillis(); 
 
    boolean isActive = false; 
    long nextActionMillis = Long.MAX_VALUE; 
//mDownloads初始化是一個(gè)空的Map<Long, DownloadInfo> 
    final Set<Long> staleIds = Sets.newHashSet(mDownloads.keySet()); 
 
    final ContentResolver resolver = getContentResolver(); 
//獲取所有的DOWNLOADS任務(wù) 
    final Cursor cursor = resolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 
        null, null, null, null); 
    try { 
      final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver, cursor); 
      final int idColumn = cursor.getColumnIndexOrThrow(Downloads.Impl._ID); 
//迭代Download Cusor 
      while (cursor.moveToNext()) { 
        final long id = cursor.getLong(idColumn); 
        staleIds.remove(id); 
 
        DownloadInfo info = mDownloads.get(id); 
//開(kāi)始時(shí),mDownloads是沒(méi)有任何內(nèi)容的,info==null 
        if (info != null) { 
//從數(shù)據(jù)庫(kù)更新最新的Download info信息,來(lái)監(jiān)聽(tīng)數(shù)據(jù)庫(kù)的改變并且反應(yīng)到界面上 
          updateDownload(reader, info, now); 
        } else { 
//添加新下載的Dwonload info到mDownloads,并且從數(shù)據(jù)庫(kù)讀取新的Dwonload info 
          info = insertDownloadLocked(reader, now); 
        } 
//這里的mDeleted參數(shù)表示的是當(dāng)我刪除了正在或者已經(jīng)下載的內(nèi)容時(shí),首先數(shù)據(jù)庫(kù)會(huì)update這個(gè)info.mDeleted為true,而不是直接刪除文件 
        if (info.mDeleted) { 
//不詳細(xì)解釋delete函數(shù),主要是刪除數(shù)據(jù)庫(kù)內(nèi)容和現(xiàn)在文件內(nèi)容 
          if (!TextUtils.isEmpty(info.mMediaProviderUri)) { 
        resolver.delete(Uri.parse(info.mMediaProviderUri), null, null); 
          } 
          deleteFileIfExists(info.mFileName); 
          resolver.delete(info.getAllDownloadsUri(), null, null); 
 
        } else { 
          // 開(kāi)始下載文件 
          final boolean activeDownload = info.startDownloadIfReady(mExecutor); 
 
          // 開(kāi)始media scanner 
          final boolean activeScan = info.startScanIfReady(mScanner); 
          isActive |= activeDownload; 
          isActive |= activeScan; 
        } 
 
        // Keep track of nearest next action 
        nextActionMillis = Math.min(info.nextActionMillis(now), nextActionMillis); 
      } 
    } finally { 
      cursor.close(); 
    } 
    // Clean up stale downloads that disappeared 
    for (Long id : staleIds) { 
      deleteDownloadLocked(id); 
    } 
    // Update notifications visible to user 
    mNotifier.updateWith(mDownloads.values()); 
    if (nextActionMillis > 0 && nextActionMillis < Long.MAX_VALUE) { 
      final Intent intent = new Intent(Constants.ACTION_RETRY); 
      intent.setClass(this, DownloadReceiver.class); 
      mAlarmManager.set(AlarmManager.RTC_WAKEUP, now + nextActionMillis, 
          PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)); 
    } 
    return isActive; 
  } 

重點(diǎn)來(lái)看看文件的下載,startDownloadIfReady函數(shù):


 public boolean startDownloadIfReady(ExecutorService executor) { 
    synchronized (this) { 
      final boolean isReady = isReadyToDownload(); 
      final boolean isActive = mSubmittedTask != null && !mSubmittedTask.isDone(); 
      if (isReady && !isActive) { 
//更新數(shù)據(jù)庫(kù)的任務(wù)狀態(tài)為STATUS_RUNNING 
        if (mStatus != Impl.STATUS_RUNNING) { 
          mStatus = Impl.STATUS_RUNNING; 
          ContentValues values = new ContentValues(); 
          values.put(Impl.COLUMN_STATUS, mStatus); 
          mContext.getContentResolver().update(getAllDownloadsUri(), values, null, null); 
        } 
//開(kāi)始下載任務(wù) 
        mTask = new DownloadThread( 
            mContext, mSystemFacade, this, mStorageManager, mNotifier); 
        mSubmittedTask = executor.submit(mTask); 
      } 
      return isReady; 
    } 
  } 

在DownloadThread的處理中,如果HTTP的狀態(tài)是ok的話(huà),會(huì)去進(jìn)行transferDate的處理。

private void transferData(State state, HttpURLConnection conn) throws StopRequestException { 
...... 
in = conn.getInputStream(); 
...... 
//獲取InputStream和OutPutStream 
if (DownloadDrmHelper.isDrmConvertNeeded(state.mMimeType)) { 
          drmClient = new DrmManagerClient(mContext); 
          final RandomAccessFile file = new RandomAccessFile( 
              new File(state.mFilename), "rw"); 
          out = new DrmOutputStream(drmClient, file, state.mMimeType); 
          outFd = file.getFD(); 
        } else { 
          out = new FileOutputStream(state.mFilename, true); 
          outFd = ((FileOutputStream) out).getFD(); 
        } 
...... 
// Start streaming data, periodically watch for pause/cancel 
      // commands and checking disk space as needed. 
      transferData(state, in, out); 
...... 
} 

------

private void transferData(State state, InputStream in, OutputStream out) 
      throws StopRequestException { 
    final byte data[] = new byte[Constants.BUFFER_SIZE]; 
    for (;;) { 
//從InputStream中讀取內(nèi)容信息,“in.read(data)”,并且對(duì)數(shù)據(jù)庫(kù)中文件下載大小進(jìn)行更新 
      int bytesRead = readFromResponse(state, data, in); 
      if (bytesRead == -1) { // success, end of stream already reached 
        handleEndOfStream(state); 
        return; 
      } 
      state.mGotData = true; 
//利用OutPutStream寫(xiě)入讀取的InputStream,"out.write(data, 0, bytesRead)" 
      writeDataToDestination(state, data, bytesRead, out); 
      state.mCurrentBytes += bytesRead; 
      reportProgress(state); 
      } 
      checkPausedOrCanceled(state); 
    } 
  } 

至此,下載文件的流程就說(shuō)完了,繼續(xù)回到DownloadService的updateLocked()函數(shù)中來(lái);重點(diǎn)來(lái)分析DownloadNotifier的updateWith()函數(shù),這個(gè)方法用來(lái)更新Notification

//這段代碼是根據(jù)不同的狀態(tài)設(shè)置不同的Notification的icon 
 if (type == TYPE_ACTIVE) { 
        builder.setSmallIcon(android.R.drawable.stat_sys_download); 
      } else if (type == TYPE_WAITING) { 
        builder.setSmallIcon(android.R.drawable.stat_sys_warning); 
      } else if (type == TYPE_COMPLETE) { 
        builder.setSmallIcon(android.R.drawable.stat_sys_download_done); 
      } 
//這段代碼是根據(jù)不同的狀態(tài)來(lái)設(shè)置不同的notification Intent 
// Build action intents 
      if (type == TYPE_ACTIVE || type == TYPE_WAITING) { 
        // build a synthetic uri for intent identification purposes 
        final Uri uri = new Uri.Builder().scheme("active-dl").appendPath(tag).build(); 
        final Intent intent = new Intent(Constants.ACTION_LIST, 
            uri, mContext, DownloadReceiver.class); 
        intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS, 
            getDownloadIds(cluster)); 
        builder.setContentIntent(PendingIntent.getBroadcast(mContext, 
            0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 
        builder.setOngoing(true); 
 
      } else if (type == TYPE_COMPLETE) { 
        final DownloadInfo info = cluster.iterator().next(); 
        final Uri uri = ContentUris.withAppendedId( 
            Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, info.mId); 
        builder.setAutoCancel(true); 
 
        final String action; 
        if (Downloads.Impl.isStatusError(info.mStatus)) { 
          action = Constants.ACTION_LIST; 
        } else { 
          if (info.mDestination != Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION) { 
            action = Constants.ACTION_OPEN; 
          } else { 
            action = Constants.ACTION_LIST; 
          } 
        } 
 
        final Intent intent = new Intent(action, uri, mContext, DownloadReceiver.class); 
        intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS, 
            getDownloadIds(cluster)); 
        builder.setContentIntent(PendingIntent.getBroadcast(mContext, 
            0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 
 
        final Intent hideIntent = new Intent(Constants.ACTION_HIDE, 
            uri, mContext, DownloadReceiver.class); 
        builder.setDeleteIntent(PendingIntent.getBroadcast(mContext, 0, hideIntent, 0)); 
      } 



//這段代碼是更新下載的Progress 
if (total > 0) { 
          final int percent = (int) ((current * 100) / total); 
          percentText = res.getString(R.string.download_percent, percent); 
 
          if (speed > 0) { 
            final long remainingMillis = ((total - current) * 1000) / speed; 
            remainingText = res.getString(R.string.download_remaining, 
                DateUtils.formatDuration(remainingMillis)); 
          } 
 
          builder.setProgress(100, percent, false); 
        } else { 
          builder.setProgress(100, 0, true); 
        } 

最后調(diào)用mNotifManager.notify(tag, 0, notif);根據(jù)不同的狀態(tài)來(lái)設(shè)置不同的Notification的title和description

 感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • Android實(shí)現(xiàn)拼圖游戲

    Android實(shí)現(xiàn)拼圖游戲

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)拼圖小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Android編程實(shí)現(xiàn)播放視頻時(shí)切換全屏并隱藏狀態(tài)欄的方法

    Android編程實(shí)現(xiàn)播放視頻時(shí)切換全屏并隱藏狀態(tài)欄的方法

    這篇文章主要介紹了Android編程實(shí)現(xiàn)播放視頻時(shí)切換全屏并隱藏狀態(tài)欄的方法,結(jié)合實(shí)例形式分析了Android視頻播放事件響應(yīng)及相關(guān)屬性設(shè)置操作技巧,需要的朋友可以參考下
    2017-08-08
  • Android應(yīng)用隱私合規(guī)檢測(cè)實(shí)現(xiàn)方案詳解

    Android應(yīng)用隱私合規(guī)檢測(cè)實(shí)現(xiàn)方案詳解

    這篇文章主要介紹了Android應(yīng)用隱私合規(guī)檢測(cè)實(shí)現(xiàn)方案,我們需要做的就是提前檢測(cè)好自己的應(yīng)用是否存在隱私合規(guī)問(wèn)題,及時(shí)整改過(guò)來(lái),下面提供Xposed Hook思路去檢測(cè)隱私合規(guī)問(wèn)題,建議有Xposed基礎(chǔ)的童鞋閱讀,需要的朋友可以參考下
    2022-07-07
  • 解析Android框架之OkHttp3源碼

    解析Android框架之OkHttp3源碼

    OkHttp3是一個(gè)處理網(wǎng)絡(luò)請(qǐng)求的開(kāi)源項(xiàng)目,是安卓端最火熱的輕量級(jí)框架。本文將詳細(xì)解析它的源碼。
    2021-06-06
  • android自定義組件實(shí)現(xiàn)儀表計(jì)數(shù)盤(pán)

    android自定義組件實(shí)現(xiàn)儀表計(jì)數(shù)盤(pán)

    這篇文章主要為大家詳細(xì)介紹了android自定義組件實(shí)現(xiàn)儀表計(jì)數(shù)盤(pán),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • 如何從UA分辨出Android設(shè)備類(lèi)型

    如何從UA分辨出Android設(shè)備類(lèi)型

    本文主要介紹如何從UA分辨出Android設(shè)備類(lèi)型,這里整理了相關(guān)資料,來(lái)講解分辨Android設(shè)備類(lèi)型,有興趣的小伙伴可以參考下
    2016-08-08
  • Android?組件化神器之Arouter依賴(lài)配置使用

    Android?組件化神器之Arouter依賴(lài)配置使用

    這篇文章主要為大家介紹了Android?組件化神器之Arouter依賴(lài)配置使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Android 界面開(kāi)發(fā)顏色整理

    Android 界面開(kāi)發(fā)顏色整理

    本文主要介紹Android 界面開(kāi)發(fā)的顏色,這里整理了很多顏色以供大家參考,希望Android 開(kāi)發(fā)的工作者可以參考使用
    2016-07-07
  • Flutter狀態(tài)管理Provider示例解析

    Flutter狀態(tài)管理Provider示例解析

    這篇文章主要為大家介紹了Flutter狀態(tài)管理Provider示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 解析ADT-20問(wèn)題 android support library

    解析ADT-20問(wèn)題 android support library

    本篇文章是對(duì)ADT-20問(wèn)題 android support library進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06

最新評(píng)論