From 0ab734f777031df95f6a2ebd6c4d5e4200dbafda Mon Sep 17 00:00:00 2001 From: huangzhuanghua <401742778@qq.com> Date: Mon, 21 Nov 2016 18:21:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8D=A2=E8=82=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gh/gamecenter/GameDetailActivity.java | 33 +- .../gamecenter/changeskin/DownloadUtils.java | 170 ++++++++ .../changeskin/GetFileMD5Utils.java | 109 +++++ .../changeskin/InitChangeSkinUtils.java | 377 ++++++++++++++++++ .../gh/gamecenter/changeskin/NetSpeed.java | 36 ++ .../gh/gamecenter/changeskin/PatchData.java | 11 + .../gh/gamecenter/changeskin/SkinConfig.java | 38 ++ .../gamecenter/entity/GameDetailEntity.java | 10 + .../gamedetail/GameDetailAdapter.java | 73 ++-- .../gamedetail/GameDetailSkinViewHolder.java | 25 ++ .../main/res/layout/gamedetail_item_skin.xml | 78 ++++ 11 files changed, 933 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/com/gh/gamecenter/changeskin/DownloadUtils.java create mode 100644 app/src/main/java/com/gh/gamecenter/changeskin/GetFileMD5Utils.java create mode 100644 app/src/main/java/com/gh/gamecenter/changeskin/InitChangeSkinUtils.java create mode 100644 app/src/main/java/com/gh/gamecenter/changeskin/NetSpeed.java create mode 100644 app/src/main/java/com/gh/gamecenter/changeskin/PatchData.java create mode 100644 app/src/main/java/com/gh/gamecenter/changeskin/SkinConfig.java create mode 100644 app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailSkinViewHolder.java create mode 100644 app/src/main/res/layout/gamedetail_item_skin.xml diff --git a/app/src/main/java/com/gh/gamecenter/GameDetailActivity.java b/app/src/main/java/com/gh/gamecenter/GameDetailActivity.java index 3c843b8c91..d74d816331 100644 --- a/app/src/main/java/com/gh/gamecenter/GameDetailActivity.java +++ b/app/src/main/java/com/gh/gamecenter/GameDetailActivity.java @@ -3,7 +3,9 @@ package com.gh.gamecenter; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.text.TextUtils; +import android.view.KeyEvent; import android.view.View; +import android.widget.RelativeLayout; import com.android.volley.Response; import com.android.volley.VolleyError; @@ -11,6 +13,8 @@ import com.gh.base.AppController; import com.gh.base.DetailActivity; import com.gh.common.constant.Config; import com.gh.common.util.DataUtils; +import com.gh.common.util.DialogUtils; +import com.gh.gamecenter.changeskin.InitChangeSkinUtils; import com.gh.gamecenter.entity.GameEntity; import com.gh.gamecenter.eventbus.EBConcernChanged; import com.gh.gamecenter.gamedetail.GameDetailAdapter; @@ -25,7 +29,6 @@ import java.util.Map; /** * Created by khy on 2016/8/12. - * 游戏详情界面 */ public class GameDetailActivity extends DetailActivity implements View.OnClickListener{ @@ -39,6 +42,8 @@ public class GameDetailActivity extends DetailActivity implements View.OnClickLi private boolean isSentReport; + private RelativeLayout actionbar_rl_back; + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -71,6 +76,7 @@ public class GameDetailActivity extends DetailActivity implements View.OnClickLi detail_tv_download.setOnClickListener(this); detail_tv_per.setOnClickListener(this); reuse_no_connection.setOnClickListener(this); + actionbar_rl_back.setOnClickListener(this); if (gameEntity != null) { adapter.setGameEntity(gameEntity); @@ -134,6 +140,15 @@ public class GameDetailActivity extends DetailActivity implements View.OnClickLi String url = "http://www.ghzhushou.com/game/" + adapter.getGameDetailEntity().getShareCode(); showShare(url, gameEntity.getName(), gameEntity.getIcon(), null, gameEntity.getTag(), entrance, "游戏"); + } else if (v == actionbar_rl_back) { + DialogUtils.showWarningDialog(GameDetailActivity.this, "退出提示", + "素材更新还在检测中,如果强行退出会中断所有进度,确定退出?", + "取消", "强行退出", new DialogUtils.ConfiremListener() { + @Override + public void onConfirem() { + finish(); + } + }, null); } } @@ -215,4 +230,20 @@ public class GameDetailActivity extends DetailActivity implements View.OnClickLi AppController.canclePendingRequests(TAG); } + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 && InitChangeSkinUtils.isChecking) { + DialogUtils.showWarningDialog(GameDetailActivity.this, "退出提示", + "素材更新还在检测中,如果强行退出会中断所有进度,确定退出?", + "取消", "强行退出", new DialogUtils.ConfiremListener() { + @Override + public void onConfirem() { + finish(); + } + }, null); + return true; + } + + return super.onKeyDown(keyCode, event); + } } diff --git a/app/src/main/java/com/gh/gamecenter/changeskin/DownloadUtils.java b/app/src/main/java/com/gh/gamecenter/changeskin/DownloadUtils.java new file mode 100644 index 0000000000..22e437b1ae --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/changeskin/DownloadUtils.java @@ -0,0 +1,170 @@ +package com.gh.gamecenter.changeskin; + +import android.os.Handler; +import android.os.Message; + +import com.gh.common.util.Utils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + + +/** + * Created by yyq on 2016/11/3. + */ +public class DownloadUtils { + + //下载需要替换的文件 + public static void saveUrlToFile(String filePath, String destUrl, Handler handler) { + int BUFFER_SIZE = 2048 * 2048; + FileOutputStream fos = null; + BufferedInputStream bis = null; + HttpURLConnection httpUrl = null; + URL url = null; + byte[] buf = new byte[ BUFFER_SIZE ]; + int size = 0; + + //建立链接 + try { + url = new URL( destUrl ); + httpUrl = (HttpURLConnection) url.openConnection(); + //连接指定的资源 + httpUrl.connect(); + //获取网络输入流 + bis = new BufferedInputStream( httpUrl.getInputStream() ); + File file = new File( filePath ); + if(!file.exists()) { + if( !file.getParentFile().exists() ) { + file.getParentFile().mkdirs(); + } + file.createNewFile(); + } + Utils.log("createNewFile::" + file.getName() + "::" + file.getAbsolutePath() + "::" + file.exists() + "::" + file.isFile()); + fos = new FileOutputStream(file); + + //保存文件 + while ( ( size = bis.read( buf ) ) != -1) + fos.write( buf, 0, size ); + Utils.log("updateProgress---saveUrlToFile"); + handler.sendEmptyMessage( SkinConfig.MSG_PROGRESS_UPDATE ); + + fos.close(); + bis.close(); + httpUrl.disconnect(); + } catch (Exception e) { + Utils.log("saveUrlToFile::" + e.toString()); + InitChangeSkinUtils.NetWorkErrorControl(); + //出现异常暂停下载 + e.printStackTrace(); + } + } + + //下载网络json + public static void downloadJson(final String params, final Handler handler ) { + + new Thread(new Runnable() { + @Override + public void run() { + InputStream is = null; + HttpURLConnection urlConnection = null; + + try { + URL url = new URL( params ); + urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setRequestMethod("GET"); + int statusCode = urlConnection.getResponseCode(); + + /* 200 represents HTTP OK */ + if (statusCode == 200) { + is = urlConnection.getInputStream(); + byte[] data = readStream(is); + String json = new String(data); + //下载完的json发送到handler + Message msg = Message.obtain(); + msg.what = SkinConfig.MSG_DOWNLOAD_OVER ; + msg.obj = json; + handler.sendMessage(msg); + }else if( statusCode == 404 ){ + handler.sendEmptyMessage(SkinConfig.MSG_DOWNLOAD_OVER); + }else if( statusCode == 302 ){ + downloadJson( params, handler ); + } + + } catch (IOException e) { + handler.sendEmptyMessage( SkinConfig.MSG_NETWORK_ERROR ); + e.printStackTrace(); + + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (urlConnection != null) { + urlConnection.disconnect(); + } + } + + } + }).start(); + + } + + + //解析json数据 + private static List parseDesPatchJson(String jsonString) { + List patchList = new ArrayList(); + JSONArray fileArray; + try { + fileArray = new JSONArray(jsonString); + for(int i = 0; i < fileArray.length(); i++ ) { + PatchData patchData = new PatchData(); + JSONObject fileObject = fileArray.getJSONObject(i); + + String md5 = fileObject.getString("md5"); + String size = fileObject.getString("size"); + String path = fileObject.getString("path"); + String url = fileObject.getString("url"); + + patchData.MD5 = md5; + patchData.size = size; + patchData.filePath = path; + patchData.url = url; + + patchList.add(patchData); + } + return patchList; + } catch (JSONException e) { + e.printStackTrace(); + return null; + } + } + + + private static byte[] readStream(InputStream inputStream) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = inputStream.read(buffer)) != -1) { + bout.write(buffer, 0, len); + } + bout.close(); + inputStream.close(); + return bout.toByteArray(); + } + +} diff --git a/app/src/main/java/com/gh/gamecenter/changeskin/GetFileMD5Utils.java b/app/src/main/java/com/gh/gamecenter/changeskin/GetFileMD5Utils.java new file mode 100644 index 0000000000..c4a43511bd --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/changeskin/GetFileMD5Utils.java @@ -0,0 +1,109 @@ +package com.gh.gamecenter.changeskin; + +import android.os.Handler; + +import java.io.File; +import java.io.FileInputStream; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by yyq on 2016/11/2. + */ +public class GetFileMD5Utils { + /** + * 获取单个文件的MD5值! + + * @param file + * @return + */ + + public static String getFileMD5(File file) { + if (!file.isFile()) { + return null; + } + MessageDigest digest = null; + FileInputStream in = null; + byte buffer[] = new byte[1024]; + int len; + try { + digest = MessageDigest.getInstance("MD5"); + in = new FileInputStream(file); + while ((len = in.read(buffer, 0, 1024)) != -1) { + digest.update(buffer, 0, len); + } + in.close(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + BigInteger bigInt = new BigInteger(1, digest.digest()); + + if(bigInt.toString().length()<39) { + int length = bigInt.toString(16).length(); + if(length < 32){ + String bigStr = bigInt.toString(16); + for(int i=0; i<(32-length); i++){ + bigStr = "0" + bigStr; + } + return bigStr; + } + } + + + return bigInt.toString(16); + } + + + + /** + * 获取文件夹中文件的MD5值 + * + * @param file + * @param listChild + * ;true递归子目录中的文件 + * @param handler + * @return + */ + public static Map getDirMD5(File file, boolean listChild, Handler handler) { + if (!file.isDirectory()) { + return null; + } + Map map = new HashMap(); + String md5; + File files[] = file.listFiles(); + for (int i = 0; i < files.length; i++) { + File f = files[i]; + if (f.isDirectory() && listChild) { + map.putAll(getDirMD5(f, listChild, handler)); + } else { + md5 = getFileMD5(f); + handler.sendEmptyMessage( SkinConfig.MSG_MD5_PROGRSS ); + if (md5 != null) { + map.put(f.getPath(), md5); + } + } + } + return map; + } + + + public static int getDirNum(File file) { + int dirNum = 0; + File files[] = file.listFiles(); + for (int i = 0; i < files.length; i++) { + File f = files[i]; + if (f.isDirectory()) { + dirNum += getDirNum(f); + } else { + dirNum ++; + } + } + return dirNum; + } + + +} diff --git a/app/src/main/java/com/gh/gamecenter/changeskin/InitChangeSkinUtils.java b/app/src/main/java/com/gh/gamecenter/changeskin/InitChangeSkinUtils.java new file mode 100644 index 0000000000..6c48c17d3c --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/changeskin/InitChangeSkinUtils.java @@ -0,0 +1,377 @@ +package com.gh.gamecenter.changeskin; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.gh.common.util.Utils; +import com.gh.gamecenter.R; +import com.gh.gamecenter.gamedetail.GameDetailSkinViewHolder; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Created by khy on 2016/11/16. + */ +public class InitChangeSkinUtils { + + private static List patchDatas = new ArrayList(); + private static List updatePatchList; + + private static Timer timer; + private static Timer poiTimer; + private static int pageNum = 1; + private static int curProgress = 0; + private static int pg = 0; + private static int maxPoogress = 0; + private static int curMD5Num; //当前检查过的本地MD5文件数量 + private static int localMD5Num;//文件总数量 + + private static ProgressBar pgPatch; + + private static String checkPoint = "."; + private static String speed = " 0kb/s"; + private static String filePath = "/mnt/sdcard/Android/data/" + SkinConfig.patchVersion + "/files"; + + private static TextView tvPatch; + private static TextView tvPer; + + private static int downPosition = -1; + private static int downState = 0; // 0:无操作 1:暂停 2:正在下载 3:下载完成 + + public static boolean isChecking = false; + + + private static Handler handler = new Handler(){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + //下载完成 + case SkinConfig.MSG_DOWNLOAD_OVER : + String jsonRuslt = (String) msg.obj; + if( "".equals(jsonRuslt) ){ + startCheckMD5Thread(); + }else { + List patchData = parseDesPatchJson(jsonRuslt); + patchDatas.addAll(patchData); + if( patchData.size() < SkinConfig.perPage ) { + startCheckMD5Thread(); + }else{ + pageNum += 1; + String urlPath = SkinConfig.JSON_PATCHURL.replace( "*", ""+pageNum ); + DownloadUtils.downloadJson( urlPath, handler ); + } + } + break; + //进度条更新 + case SkinConfig.MSG_PROGRESS_UPDATE : + tvPatch.setVisibility(View.GONE); + pgPatch.setVisibility(View.VISIBLE); + tvPer.setVisibility(View.VISIBLE); + curProgress++; + pg = curProgress * 100 / maxPoogress; + pgPatch.setProgress(pg); + Utils.log("当前下载:" + pg + "% (" + speed + ")" + "::" + curProgress); + if (pg >= 100) { + tvPatch.setText("更新完成"); + tvPatch.setVisibility(View.VISIBLE); + pgPatch.setVisibility(View.GONE); + tvPer.setVisibility(View.GONE); + tvPatch.setEnabled(false); + pgPatch.setEnabled(false); + tvPer.setEnabled(false); + downState = 3; + timer.cancel(); + } else { + if (downState == 1) { + tvPer.setText("继续"); + } else { + tvPer.setText( pg + "% (" + speed + ")" ); + } + } + break; + //更新下载速度 + case SkinConfig.MSG_NETWORK_SPEED : + speed = (String) msg.obj; + break; + //更新检测当前文件MD5值数量 + case SkinConfig.MSG_MD5_PROGRSS : + curMD5Num++; + String showTxt = "检测中(" + curMD5Num + "/" + localMD5Num + ")" + checkPoint; + changeViewState(showTxt, "blue", SkinConfig.TYPE_DESUPDATE, false); + break; + //文件MD5值检查完 + case SkinConfig.MSG_MD5_OVER : + poiTimer.cancel(); + Map map = (Map) msg.obj; + relMD5File( map ); + break; + //网络error + case SkinConfig.MSG_NETWORK_ERROR : + changeViewState( "网络异常,请保持网络通畅", "gray", SkinConfig.TYPE_DESUPDATE, true ); + break; + } + } + }; + + public static void changeSkinControl(GameDetailSkinViewHolder holder, final Context context){ + + tvPatch = holder.skinDownloadTv; + pgPatch = holder.skinDownloadPb; + tvPer = holder.skinDownloadPerTv; + pgPatch.setMax(100); + + if (downState == 0) { + tvPatch.setText("检查更新"); + tvPatch.setVisibility(View.VISIBLE); + pgPatch.setVisibility(View.GONE); + tvPer.setVisibility(View.GONE); + } else if (downState == 1) { + tvPatch.setVisibility(View.GONE); + pgPatch.setVisibility(View.VISIBLE); + tvPer.setVisibility(View.VISIBLE); + pgPatch.setProgress( pg ); + tvPer.setText("继续"); + } else if (downState == 2){ + tvPatch.setVisibility(View.GONE); + pgPatch.setVisibility(View.VISIBLE); + tvPer.setVisibility(View.VISIBLE); + tvPer.setText( pg + "% (" + speed + ")" ); + } else if (downState == 3) { + tvPatch.setText("更新完成"); + tvPatch.setVisibility(View.VISIBLE); + pgPatch.setVisibility(View.GONE); + tvPer.setVisibility(View.GONE); + } + + holder.skinDownloadTv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if ("更新完成".equals(tvPatch.getText().toString())) return; + switch ( SkinConfig.PG_STATE ){ + case SkinConfig.TYPE_DESUPDATE : + if (!"检查更新".equals(tvPatch.getText().toString())) return; + // /data/data目录下包名文件 + File pgFile = new File( "/data/data/" + SkinConfig.patchVersion ); + // 内部sdcard中版本文件 + String pgFilePath = "/mnt/sdcard/Android/data/" + SkinConfig.patchVersion + "/files"; + File verFile = new File( pgFilePath ); + if( !pgFile.exists() || !verFile.exists() ) { + String showTxt = "请先安装游戏,并更新好所有补丁"; + tvPatch.setBackgroundResource(R.drawable.textview_cancel_style); + changeViewState( showTxt, "gray", SkinConfig.TYPE_DESUPDATE, true ); + } else { + isChecking = true; + String showTxt = "检测中" + checkPoint; + changeViewState( showTxt, "blue", SkinConfig.TYPE_DESUPDATE, false ); + startSetPoint(); + + String urlPath = SkinConfig.JSON_PATCHURL.replace( "*", ""+pageNum ); + //下载数据json + DownloadUtils.downloadJson( urlPath, handler); + } + break; + case SkinConfig.TYPE_UPDATE : + String showTxt = "开始更新..."; + changeViewState( showTxt, "blue", SkinConfig.TYPE_DESUPDATE, false ); + maxPoogress = updatePatchList.size(); + startTimer(context); + + updateProgress(); + break; + } + } + }); + + tvPer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if ("继续".equals(tvPer.getText().toString())){ + downState = 2; + tvPer.setText( pg + "% (" + speed + ")" ); + updateProgress(); + } else { + tvPer.setText("继续"); + downState = 1; + } + } + }); + + } + + //按钮状态改变 + private static void changeViewState( String txt, String color, int type, boolean isEnabled) { + tvPatch.setText( txt ); + SkinConfig.PG_STATE = type; + pgPatch.setEnabled( isEnabled ); + } + + //正在下载 ... 点用计时器控制 + private static void startSetPoint(){ + final int[] curPoint = {0}; + final TimerTask task = new TimerTask() { + @Override + public void run() { + + curPoint[0] += 1; + if(curPoint[0] == 1){ + checkPoint = "."; + }else if(curPoint[0] == 2){ + checkPoint = ".."; + }else if(curPoint[0] == 3){ + curPoint[0] = 0; + checkPoint = "..."; + } + } + }; + poiTimer = new Timer( true ); + poiTimer.schedule( task, 1000, 1000 ); + } + + //开启计时器,计算下载速度 + private static void startTimer(final Context context) { + + final TimerTask task = new TimerTask() { + @Override + public void run() { + NetSpeed.showNetSpeed(context, handler); + } + }; + timer = new Timer( true ); + timer.schedule( task, 1000, 1000 ); + } + + //比较文件的MD5值,返回MD5值不同的文件个数 + private static void relMD5File( Map dirMD5Map ) { + updatePatchList = new ArrayList(); + int patchSize = 0; + curMD5Num = 0; + //获取目录下所有文件的 MD5 值 + for ( int i = 0; i < patchDatas.size(); i++ ) { + PatchData data = patchDatas.get( i ); + String path = data.filePath; + String updateMD5 = data.MD5; + String updateUrl = data.url; + String updateSize = data.size; + + //替换地址中标识符& + String replacePath = path.replace("&", SkinConfig.patchVersion); + patchDatas.get(i).filePath = replacePath; + + String localMD5 = dirMD5Map.get( "/" + replacePath ); + if ( localMD5 != null ) { + if ( !updateMD5.equals( localMD5 ) ) { + updatePatchList.add( data ); + patchSize += Integer.parseInt( updateSize ); + } + } + } + + isChecking = false; + + if (patchSize == 0) { + String showTxt = "暂无更新"; + tvPatch.setBackgroundResource(R.drawable.textview_cancel_style); + changeViewState( showTxt, "gray", SkinConfig.TYPE_DESUPDATE, true); + } else { + patchSize = patchSize / 1024 / 1024; + String showTxt = "点击开始更新(" + patchSize + "MB)"; + changeViewState( showTxt, "blue", SkinConfig.TYPE_UPDATE, true ); + } + } + + private static void startCheckMD5Thread(){ + final Thread checkMD5Thrad = new Thread(new Runnable() { + @Override + public void run() { + localMD5Num = GetFileMD5Utils.getDirNum(new File(filePath)); + Map dirMD5Map = GetFileMD5Utils.getDirMD5(new File(filePath), true, handler); + Message msg = Message.obtain(); + msg.obj = dirMD5Map; + msg.what = SkinConfig.MSG_MD5_OVER; + handler.sendMessage(msg); + } + }); + checkMD5Thrad.start(); + } + + //解析json数据 + private static List parseDesPatchJson(String jsonString) { + List patchList = new ArrayList(); + JSONArray fileArray; + try { + fileArray = new JSONArray(jsonString); + for(int i = 0; i < fileArray.length(); i++ ) { + PatchData patchData = new PatchData(); + JSONObject fileObject = fileArray.getJSONObject(i); + + String md5 = fileObject.getString("md5"); + String size = fileObject.getString("size"); + String path = fileObject.getString("path"); + String url = fileObject.getString("url"); + + patchData.MD5 = md5; + patchData.size = size; + patchData.filePath = path; + patchData.url = url; + + patchList.add(patchData); + } + return patchList; + } catch (JSONException e) { + e.printStackTrace(); + return null; + } + } + + //指定目录,下载替换文件 + private static void updateProgress() { + + Thread downThread = new Thread(new Runnable() { + @Override + public void run() { + for( int i = 0; i < updatePatchList.size(); i++ ) { + if (downState == 1) { + break; + } + if (i < downPosition) { // 重复下载暂停前的一张图片,防止断网下载失败 漏掉下载的图片 + continue; + } + downPosition = i; + + PatchData patchData = updatePatchList.get( i ); + String filePath = patchData.filePath; + Utils.log("updateProgress---" + updatePatchList.size() + "::" + i); + DownloadUtils.saveUrlToFile( filePath, patchData.url, handler ); + } + } + }); + downThread.start(); + } + + //断网或者写入文件失败的操作 + public static void NetWorkErrorControl (){ + downState = 1; + handler.post(new Runnable() { + @Override + public void run() { + tvPer.setText("继续"); + } + }); + + } +} diff --git a/app/src/main/java/com/gh/gamecenter/changeskin/NetSpeed.java b/app/src/main/java/com/gh/gamecenter/changeskin/NetSpeed.java new file mode 100644 index 0000000000..8f2da730d9 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/changeskin/NetSpeed.java @@ -0,0 +1,36 @@ +package com.gh.gamecenter.changeskin; + +import android.content.Context; +import android.net.TrafficStats; +import android.os.Handler; +import android.os.Message; + + +/** + * Created by yyq on 2016/11/4. + */ +public class NetSpeed { + + private static long lastTotalRxBytes = 0; + private static long lastTimeStamp = 0; + + private static long getTotalRxBytes(Context context) { + return TrafficStats.getUidRxBytes( context.getApplicationInfo().uid ) == TrafficStats.UNSUPPORTED ? 0 : (TrafficStats.getTotalRxBytes() / 1024);//转为KB + } + + public static void showNetSpeed(Context context, Handler handler) { + + long nowTotalRxBytes = getTotalRxBytes( context ); + long nowTimeStamp = System.currentTimeMillis(); + long speed = ((nowTotalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));//毫秒转换 + + lastTimeStamp = nowTimeStamp; + lastTotalRxBytes = nowTotalRxBytes; + + Message msg = handler.obtainMessage(); + msg.what = SkinConfig.MSG_NETWORK_SPEED ; + String speeds = String.valueOf(speed) + " kb/s"; + msg.obj = speeds; + handler.sendMessage(msg);//更新界面 + } +} diff --git a/app/src/main/java/com/gh/gamecenter/changeskin/PatchData.java b/app/src/main/java/com/gh/gamecenter/changeskin/PatchData.java new file mode 100644 index 0000000000..09b10f536b --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/changeskin/PatchData.java @@ -0,0 +1,11 @@ +package com.gh.gamecenter.changeskin; + +/** + * Created by yyq on 2016/11/2. + */ +public class PatchData { + public String MD5; + public String size; + public String filePath; + public String url; +} diff --git a/app/src/main/java/com/gh/gamecenter/changeskin/SkinConfig.java b/app/src/main/java/com/gh/gamecenter/changeskin/SkinConfig.java new file mode 100644 index 0000000000..3f4cfda5d7 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/changeskin/SkinConfig.java @@ -0,0 +1,38 @@ +package com.gh.gamecenter.changeskin; + +/** + * Created by khy on 2016/11/16. + */ +public class SkinConfig { + + public static int PG_STATE = 1; + + /* + pageNum : 页数 + perPage : 请求数量 + */ + public static int perPage = 300; + + + public static final int TYPE_DESUPDATE = 1; + public static final int TYPE_UPDATE = 2; + public static final int TYPE_STOP = 3; + public static final int TYPE_RESTART = 4; + + public static final int MSG_DOWNLOAD_OVER = 100; + public static final int MSG_PROGRESS_UPDATE = 101; + public static final int MSG_NETWORK_SPEED = 102; + public static final int MSG_MD5_PROGRSS = 103; + public static final int MSG_MD5_OVER = 104; + public static final int MSG_NETWORK_ERROR = 200; + + public static String GAME_ID = "57ce84f88ab49e83728b4572"; + + // http://api.ghzhushou.com/v2d2/game/57ce84f88ab49e83728b4572/skin/data?page=1&per_page=1000 + public static String JSON_PATCHURL = "http://api.ghzhushou.com/v2d2/game/" + GAME_ID + "/skin/data?page=*&per_page=" + perPage; + + // ewan.anfeng 安峰 + public static String patchVersion = "com.netease.ma.ewan.anfeng"; + // public static String patchVersion = "com.netease.ma.bili"; + +} diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameDetailEntity.java b/app/src/main/java/com/gh/gamecenter/entity/GameDetailEntity.java index 5acca8cd7c..534f918990 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/GameDetailEntity.java +++ b/app/src/main/java/com/gh/gamecenter/entity/GameDetailEntity.java @@ -20,6 +20,16 @@ public class GameDetailEntity { private String shareCode; @SerializedName("download_off_text") private String downloadOffText; + @SerializedName("skin_test") + private boolean skinTest; + + public boolean isSkinTest() { + return skinTest; + } + + public void setSkinTest(boolean skinTest) { + this.skinTest = skinTest; + } public void setDownloadOffText(String downloadOffText) { this.downloadOffText = downloadOffText; diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailAdapter.java b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailAdapter.java index 7a1119a6bc..d670a66167 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailAdapter.java @@ -31,6 +31,7 @@ import com.gh.common.view.HorizontalItemDecoration; import com.gh.gamecenter.GameDetailActivity; import com.gh.gamecenter.GameNewsActivity; import com.gh.gamecenter.R; +import com.gh.gamecenter.changeskin.InitChangeSkinUtils; import com.gh.gamecenter.entity.ApkEntity; import com.gh.gamecenter.entity.GameDetailEntity; import com.gh.gamecenter.entity.GameEntity; @@ -60,7 +61,6 @@ import java.util.Map; /** * Created by LGT on 2016/9/8. - * 游戏详情界面-数据适配器 */ public class GameDetailAdapter extends RecyclerView.Adapter { @@ -233,8 +233,12 @@ public class GameDetailAdapter extends RecyclerView.Adapter { return new GameDetailNewsViewHolder(view); } else if (viewType == 5) { View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.gamedetail_item_intro,parent,false); + .inflate(R.layout.gamedetail_item_intro, parent, false); return new GameDetailIntroViewHolder(view); + } else if (viewType == 6) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.gamedetail_item_skin, parent, false); + return new GameDetailSkinViewHolder(view); } return null; } @@ -251,9 +255,15 @@ public class GameDetailAdapter extends RecyclerView.Adapter { initIntroViewHolder((GameDetailIntroViewHolder) holder); } else if (holder instanceof GameDetailNewsServerViewHolder) { initNewsServerViewHolder((GameDetailNewsServerViewHolder) holder); + } else if (holder instanceof GameDetailSkinViewHolder) { + initSkinViewHolder((GameDetailSkinViewHolder) holder); } } + private void initSkinViewHolder(GameDetailSkinViewHolder holder) { + InitChangeSkinUtils.changeSkinControl(holder, context); + } + private void initNewsServerViewHolder(final GameDetailNewsServerViewHolder viewHolder) { ArrayList serverInfo = gameDetailEntity.getServerInfo(); viewHolder.gamedetail_newsserver_show.setLayoutManager(new LinearLayoutManager( @@ -508,7 +518,7 @@ public class GameDetailAdapter extends RecyclerView.Adapter { } @Override - public PluginAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.HORIZONTAL); LinearLayout.LayoutParams llParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(context, 28)); @@ -540,7 +550,7 @@ public class GameDetailAdapter extends RecyclerView.Adapter { } @Override - public void onBindViewHolder(PluginAdapter.ViewHolder holder, int position) { + public void onBindViewHolder(ViewHolder holder, int position) { holder.pluginTitle.setText(tags.get(position).getName()); holder.pluginIcon.setImageURI(tags.get(position).getIcon()); } @@ -615,16 +625,16 @@ public class GameDetailAdapter extends RecyclerView.Adapter { String uuid = TokenUtils.getDeviceId(context); ConcernUtils.postConcernGameId(gameEntity.getId(), Config.HOST + "device/" + uuid + "/concern", new ConcernUtils.DownJsonListener() { - @Override - public void downSucced(String str) { - Utils.log("关注提交成功==游戏详情"); - } + @Override + public void downSucced(String str) { + Utils.log("关注提交成功==游戏详情"); + } - @Override - public void downFailed() { - Utils.log("关注提交失败==游戏详情"); - } - }); + @Override + public void downFailed() { + Utils.log("关注提交失败==游戏详情"); + } + }); } else { Map kv2 = new HashMap<>(); kv2.put("点击", "取消关注"); @@ -652,16 +662,16 @@ public class GameDetailAdapter extends RecyclerView.Adapter { String uuid = TokenUtils.getDeviceId(context); ConcernUtils.deleteConcernData(Config.HOST + "device/" + uuid + "/concern/" + gameEntity.getId(), new ConcernUtils.DownJsonListener() { - @Override - public void downSucced(String str) { - Utils.log("删除提交成功==游戏详情"); - } + @Override + public void downSucced(String str) { + Utils.log("删除提交成功==游戏详情"); + } - @Override - public void downFailed() { - Utils.log("删除提交失败==游戏详情"); - } - }); + @Override + public void downFailed() { + Utils.log("删除提交失败==游戏详情"); + } + }); } }); } @@ -736,25 +746,36 @@ public class GameDetailAdapter extends RecyclerView.Adapter { if (position_intro != -1) { index++; } + if (position_top != -1 && gameDetailEntity.isSkinTest()) { + index++; + } return index; } } @Override public int getItemViewType(int position) { + int index = 0; + if (position_top != -1 && gameDetailEntity.isSkinTest()) { + index = 1; + } + if (position_top != -1 && position == position_top) { return 1; } - if (position_newsserver != -1 && position == position_newsserver) { + if (position_top != -1 && gameDetailEntity.isSkinTest() && position == position_top + 1) { + return 6; + } + if (position_newsserver != -1 && position == position_newsserver + index) { return 2; } - if (position_plugin != -1 && position == position_plugin) { + if (position_plugin != -1 && position == position_plugin + index) { return 3; } - if (position_news != -1 && position == position_news) { + if (position_news != -1 && position == position_news + index) { return 4; } - if (position_intro != -1 && position == position_intro) { + if (position_intro != -1 && position == position_intro + index) { return 5; } return position; diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailSkinViewHolder.java b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailSkinViewHolder.java new file mode 100644 index 0000000000..6c878b4198 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailSkinViewHolder.java @@ -0,0 +1,25 @@ +package com.gh.gamecenter.gamedetail; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.gh.gamecenter.R; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Created by khy on 2016/11/16. + */ +public class GameDetailSkinViewHolder extends RecyclerView.ViewHolder{ + @BindView(R.id.skin_tv_download) public TextView skinDownloadTv; + @BindView(R.id.skin_pb_progressbar) public ProgressBar skinDownloadPb; + @BindView(R.id.skin_tv_per) public TextView skinDownloadPerTv; + + public GameDetailSkinViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } +} diff --git a/app/src/main/res/layout/gamedetail_item_skin.xml b/app/src/main/res/layout/gamedetail_item_skin.xml new file mode 100644 index 0000000000..8a8ae1e2cb --- /dev/null +++ b/app/src/main/res/layout/gamedetail_item_skin.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file