Commit 95d458e16a02b71b6d76ebbd96850b0ec7b170c6

Authored by 陈硕
2 parents b0c461a7 f79818f5

合并代码

Showing 48 changed files with 1017 additions and 128 deletions
.idea/modules.xml
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 <component name="ProjectModuleManager"> 3 <component name="ProjectModuleManager">
4 <modules> 4 <modules>
5 <module fileurl="file://$PROJECT_DIR$/CNLiveApp.iml" filepath="$PROJECT_DIR$/CNLiveApp.iml" /> 5 <module fileurl="file://$PROJECT_DIR$/CNLiveApp.iml" filepath="$PROJECT_DIR$/CNLiveApp.iml" />
6 - <module fileurl="file://$PROJECT_DIR$/CNLiveApp5.iml" filepath="$PROJECT_DIR$/CNLiveApp5.iml" />  
7 <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> 6 <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
8 <module fileurl="file://$PROJECT_DIR$/user/user.iml" filepath="$PROJECT_DIR$/user/user.iml" /> 7 <module fileurl="file://$PROJECT_DIR$/user/user.iml" filepath="$PROJECT_DIR$/user/user.iml" />
9 </modules> 8 </modules>
app/build.gradle
@@ -30,11 +30,8 @@ dependencies { @@ -30,11 +30,8 @@ dependencies {
30 compile 'com.android.support.constraint:constraint-layout:1.0.2' 30 compile 'com.android.support.constraint:constraint-layout:1.0.2'
31 compile 'com.github.bumptech.glide:glide:3.7.0' 31 compile 'com.github.bumptech.glide:glide:3.7.0'
32 compile 'org.greenrobot:eventbus:3.0.0' 32 compile 'org.greenrobot:eventbus:3.0.0'
33 - compile files('libs/libcnliveuser.jar')  
34 - //Smack  
35 - compile 'org.igniterealtime.smack:smack-android-extensions:4.1.4'  
36 - compile 'org.igniterealtime.smack:smack-tcp:4.1.4'  
37 - compile 'org.greenrobot:greendao-encryption:2.2.2'  
38 - compile 'com.gyf.barlibrary:barlibrary:2.2.4'  
39 - compile project(':user') 33 +
  34 + compile 'com.squareup.retrofit2:retrofit:2.3.0'
  35 + compile 'com.squareup.retrofit2:converter-gson:2.3.0'
  36 +
40 } 37 }
app/src/main/AndroidManifest.xml
@@ -26,21 +26,10 @@ @@ -26,21 +26,10 @@
26 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 26 <uses-permission android:name="android.permission.READ_PHONE_STATE" />
27 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 27 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
28 28
29 - <uses-permission android:name="android.permission.INTERNET" />  
30 -  
31 <!-- account start --> 29 <!-- account start -->
32 - <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />  
33 - <uses-permission android:name="android.permission.GET_ACCOUNTS" />  
34 - <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />  
35 - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />  
36 - <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />  
37 <uses-permission 30 <uses-permission
38 android:name="android.permission.ACCOUNT_MANAGER" 31 android:name="android.permission.ACCOUNT_MANAGER"
39 tools:ignore="ProtectedPermissions" /> 32 tools:ignore="ProtectedPermissions" />
40 - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
41 - <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
42 - <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
43 - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
44 33
45 <application 34 <application
46 android:name=".main.application.CNLiveApplication" 35 android:name=".main.application.CNLiveApplication"
app/src/main/java/com/cnlive/gundam/main/model/ActivePlayInfo.java 0 → 100644
  1 +package com.cnlive.gundam.main.model;
  2 +
  3 +
  4 +
  5 +import java.io.Serializable;
  6 +
  7 +/**
  8 + * Created by Lynn on 5/27/2017.
  9 + */
  10 +
  11 +public class ActivePlayInfo extends ErrorMessage {
  12 +
  13 + private ActiveModel data;
  14 +
  15 + public ActivePlayInfo() {
  16 +
  17 + }
  18 +
  19 + public ActiveModel getData() {
  20 + return data;
  21 + }
  22 +
  23 + public void setData(ActiveModel data) {
  24 + this.data = data;
  25 + }
  26 +
  27 + public class ActiveModel implements Serializable {
  28 + private String activityId;
  29 + private String activityName;
  30 + private int activityStatus;
  31 + private int isHorizontalScreen;
  32 + private String channelId;
  33 + private String createTime;
  34 + private String startTime;
  35 + private String endTime;
  36 + private String coverImgUrl;
  37 + private String activityCategory;
  38 + private String extensions;
  39 + private String rates;
  40 + private String extViews;
  41 +
  42 + public ActiveModel() {
  43 + }
  44 +
  45 + public String getActivityId() {
  46 + return activityId;
  47 + }
  48 +
  49 + public void setActivityId(String activityId) {
  50 + this.activityId = activityId;
  51 + }
  52 +
  53 + public String getActivityName() {
  54 + return activityName;
  55 + }
  56 +
  57 + public void setActivityName(String activityName) {
  58 + this.activityName = activityName;
  59 + }
  60 +
  61 + public int getActivityStatus() {
  62 + return activityStatus;
  63 + }
  64 +
  65 + public void setActivityStatus(int activityStatus) {
  66 + this.activityStatus = activityStatus;
  67 + }
  68 +
  69 + public int getIsHorizontalScreen() {
  70 + return isHorizontalScreen;
  71 + }
  72 +
  73 + public void setIsHorizontalScreen(int isHorizontalScreen) {
  74 + this.isHorizontalScreen = isHorizontalScreen;
  75 + }
  76 +
  77 + public String getChannelId() {
  78 + return channelId;
  79 + }
  80 +
  81 + public void setChannelId(String channelId) {
  82 + this.channelId = channelId;
  83 + }
  84 +
  85 + public String getCreateTime() {
  86 + return createTime;
  87 + }
  88 +
  89 + public void setCreateTime(String createTime) {
  90 + this.createTime = createTime;
  91 + }
  92 +
  93 + public String getStartTime() {
  94 + return startTime;
  95 + }
  96 +
  97 + public void setStartTime(String startTime) {
  98 + this.startTime = startTime;
  99 + }
  100 +
  101 + public String getEndTime() {
  102 + return endTime;
  103 + }
  104 +
  105 + public void setEndTime(String endTime) {
  106 + this.endTime = endTime;
  107 + }
  108 +
  109 + public String getCoverImgUrl() {
  110 + return coverImgUrl;
  111 + }
  112 +
  113 + public void setCoverImgUrl(String coverImgUrl) {
  114 + this.coverImgUrl = coverImgUrl;
  115 + }
  116 +
  117 + public String getActivityCategory() {
  118 + return activityCategory;
  119 + }
  120 +
  121 + public void setActivityCategory(String activityCategory) {
  122 + this.activityCategory = activityCategory;
  123 + }
  124 +
  125 + public String getExtensions() {
  126 + return extensions;
  127 + }
  128 +
  129 + public void setExtensions(String extensions) {
  130 + this.extensions = extensions;
  131 + }
  132 +
  133 + public String getRates() {
  134 + return rates;
  135 + }
  136 +
  137 + public void setRates(String rates) {
  138 + this.rates = rates;
  139 + }
  140 +
  141 + public String getExtViews() {
  142 + return extViews;
  143 + }
  144 +
  145 + public void setExtViews(String extViews) {
  146 + this.extViews = extViews;
  147 + }
  148 +
  149 + @Override
  150 + public String toString() {
  151 + return "ActiveModel{" +
  152 + "activityId='" + activityId + '\'' +
  153 + ", activityName='" + activityName + '\'' +
  154 + ", activityStatus=" + activityStatus +
  155 + ", isHorizontalScreen=" + isHorizontalScreen +
  156 + ", channelId='" + channelId + '\'' +
  157 + ", createTime='" + createTime + '\'' +
  158 + ", startTime='" + startTime + '\'' +
  159 + ", endTime='" + endTime + '\'' +
  160 + ", coverImgUrl='" + coverImgUrl + '\'' +
  161 + ", activityCategory='" + activityCategory + '\'' +
  162 + ", extensions='" + extensions + '\'' +
  163 + ", rates='" + rates + '\'' +
  164 + ", extViews='" + extViews + '\'' +
  165 + '}';
  166 + }
  167 + }
  168 +
  169 + @Override
  170 + public String toString() {
  171 + return "ActivePlayInfo{" +
  172 + "data=" + data +
  173 + '}';
  174 + }
  175 +}
app/src/main/java/com/cnlive/gundam/main/model/VideoListProgram.java
@@ -8,21 +8,21 @@ import java.io.Serializable; @@ -8,21 +8,21 @@ import java.io.Serializable;
8 */ 8 */
9 9
10 public class VideoListProgram implements Serializable { 10 public class VideoListProgram implements Serializable {
11 - //点播的id  
12 - private String vId;  
13 - //直播的id  
14 - private String channelId; 11 +
  12 + private String vId;//点播的id
  13 + private String channelId;//直播的id
15 private String title; 14 private String title;
16 private String subTitle; 15 private String subTitle;
17 private String img; 16 private String img;
18 - //直播使用  
19 - private String docID; 17 + private String docID;//直播使用
20 private String rates; 18 private String rates;
21 private String type; 19 private String type;
  20 + private String category;//点播用
22 21
23 public VideoListProgram() { 22 public VideoListProgram() {
24 } 23 }
25 24
  25 + //ugc点播使用
26 public VideoListProgram(String vId, String title, String img, String subTitle, String rates, String type) { 26 public VideoListProgram(String vId, String title, String img, String subTitle, String rates, String type) {
27 this.vId = vId; 27 this.vId = vId;
28 this.title = title; 28 this.title = title;
@@ -32,6 +32,7 @@ public class VideoListProgram implements Serializable { @@ -32,6 +32,7 @@ public class VideoListProgram implements Serializable {
32 this.type = type; 32 this.type = type;
33 } 33 }
34 34
  35 + //直播使用
35 public VideoListProgram(String channelId, String title, String img, String docID, String type) { 36 public VideoListProgram(String channelId, String title, String img, String docID, String type) {
36 this.channelId = channelId; 37 this.channelId = channelId;
37 this.title = title; 38 this.title = title;
app/src/main/java/com/cnlive/gundam/main/model/VodListPage.java 0 → 100644
  1 +package com.cnlive.gundam.main.model;
  2 +
  3 +import java.util.List;
  4 +
  5 +/**
  6 + * Created by gujun on 2017/6/28.
  7 + */
  8 +
  9 +public class VodListPage extends ErrorMessage {
  10 +
  11 + private List<VideoListProgram> data;
  12 +
  13 + public List<VideoListProgram> getData() {
  14 + return data;
  15 + }
  16 +
  17 + public void setData(List<VideoListProgram> data) {
  18 + this.data = data;
  19 + }
  20 +}
app/src/main/java/com/cnlive/gundam/main/network/ApiService.java 0 → 100644
  1 +package com.cnlive.gundam.main.network;
  2 +
  3 +import com.cnlive.gundam.main.model.ActiveListModel;
  4 +import com.cnlive.gundam.main.model.ActivePlayInfo;
  5 +import com.cnlive.gundam.main.model.VodListPage;
  6 +
  7 +import java.util.Map;
  8 +
  9 +import retrofit2.Call;
  10 +import retrofit2.http.GET;
  11 +import retrofit2.http.QueryMap;
  12 +
  13 +/**
  14 + * Created by gujun on 2017/6/28.
  15 + */
  16 +
  17 +public interface ApiService {
  18 +
  19 + //获取sp对应下的活动列表
  20 + @GET("live_epg/sp/activityList4App")
  21 + Call<ActiveListModel> getSpActivityList(@QueryMap Map<String, String> options);
  22 +
  23 + //判断活动的状态
  24 + @GET("live_epg/getLiveActivityPlayInfo4App")
  25 + Call<ActivePlayInfo> getActivityPlayInfo(@QueryMap Map<String, String> options);
  26 +
  27 + //判断活动的状态
  28 + @GET("vod_epg/getVodInfo4App")
  29 + Call<VodListPage> getVodInfoList(@QueryMap Map<String, String> options);
  30 +}
app/src/main/java/com/cnlive/gundam/main/network/RetrofitUtil.java 0 → 100644
  1 +package com.cnlive.gundam.main.network;
  2 +
  3 +import okhttp3.OkHttpClient;
  4 +import retrofit2.Retrofit;
  5 +import retrofit2.converter.gson.GsonConverterFactory;
  6 +
  7 +/**
  8 + * Created by gujun on 2017/6/28.
  9 + */
  10 +
  11 +public class RetrofitUtil {
  12 +
  13 + private static final String BASE_URL = "http://test.open.cnlive.com/openapi/api2/";
  14 +
  15 + public static ApiService getApiService(){
  16 + Retrofit retrofit = new Retrofit.Builder()
  17 + .baseUrl(BASE_URL)
  18 + .addConverterFactory(GsonConverterFactory.create())
  19 + .client(new OkHttpClient())
  20 + .build();
  21 + return retrofit.create(ApiService.class);
  22 + }
  23 +}
app/src/main/java/com/cnlive/gundam/main/network/util/SHA1.java 0 → 100644
  1 +package com.cnlive.gundam.main.network.util;
  2 +
  3 +import java.io.UnsupportedEncodingException;
  4 +import java.math.BigInteger;
  5 +import java.security.MessageDigest;
  6 +import java.security.NoSuchAlgorithmException;
  7 +
  8 +public class SHA1 {
  9 + private final int[] abcde = {0x67452301, 0xefcdab89, 0x98badcfe,
  10 + 0x10325476, 0xc3d2e1f0};
  11 +
  12 + // 摘要数据存储数组
  13 + private int[] digestInt = new int[5];
  14 +
  15 + // 计算过程中的临时数据存储数组
  16 + private int[] tmpData = new int[80];
  17 +
  18 + /**
  19 + * 将字节转换为十六进制字符串
  20 + *
  21 + * @param ib
  22 + * @return
  23 + */
  24 + private static String byteToHexString(byte ib) {
  25 + char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
  26 + 'B', 'C', 'D', 'E', 'F'};
  27 + char[] ob = new char[2];
  28 + ob[0] = Digit[(ib >>> 4) & 0X0F];
  29 + ob[1] = Digit[ib & 0X0F];
  30 + String s = new String(ob);
  31 + return s;
  32 + }
  33 +
  34 + /**
  35 + * 将字节数组转换为十六进制字符串
  36 + *
  37 + * @param bytearray
  38 + * @return
  39 + */
  40 + private static String byteArrayToHexString(byte[] bytearray) {
  41 + String strDigest = "";
  42 + for (byte aBytearray : bytearray) {
  43 + strDigest += byteToHexString(aBytearray);
  44 + }
  45 + return strDigest;
  46 + }
  47 +
  48 + /**
  49 + * @param text
  50 + * @return
  51 + */
  52 + public static String SHA1Digest(String text) {
  53 + String pwd = "";
  54 + try {
  55 + MessageDigest md = MessageDigest.getInstance("SHA1");
  56 + md.update(text.getBytes());
  57 + pwd = new BigInteger(1, md.digest()).toString(16);
  58 + } catch (NoSuchAlgorithmException e) {
  59 + e.printStackTrace();
  60 + }
  61 + return pwd;
  62 + }
  63 +
  64 + /**
  65 + * 计算sha-1摘要
  66 + *
  67 + * @param bytedata
  68 + * @return
  69 + */
  70 + private int process_input_bytes(byte[] bytedata) {
  71 + // 初试化常量
  72 + System.arraycopy(abcde, 0, digestInt, 0, abcde.length);
  73 + // 格式化输入字节数组,补10及长度数据
  74 + byte[] newbyte = byteArrayFormatData(bytedata);
  75 + // 获取数据摘要计算的数据单元个数
  76 + int MCount = newbyte.length / 64;
  77 + // 循环对每个数据单元进行摘要计算
  78 + for (int pos = 0; pos < MCount; pos++) {
  79 + // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中
  80 + for (int j = 0; j < 16; j++) {
  81 + tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4));
  82 + }
  83 + // 摘要计算函数
  84 + encrypt();
  85 + }
  86 + return 20;
  87 + }
  88 +
  89 + /**
  90 + * 格式化输入字节数组格式
  91 + *
  92 + * @param bytedata
  93 + * @return
  94 + */
  95 + private byte[] byteArrayFormatData(byte[] bytedata) {
  96 + // 补0数量
  97 + int zeros = 0;
  98 + // 补位后总位数
  99 + int size = 0;
  100 + // 原始数据长度
  101 + int n = bytedata.length;
  102 + // 模64后的剩余位数
  103 + int m = n % 64;
  104 + // 计算添加0的个数以及添加10后的总长度
  105 + if (m < 56) {
  106 + zeros = 55 - m;
  107 + size = n - m + 64;
  108 + } else if (m == 56) {
  109 + zeros = 63;
  110 + size = n + 8 + 64;
  111 + } else {
  112 + zeros = 63 - m + 56;
  113 + size = (n + 64) - m + 64;
  114 + }
  115 + // 补位后生成的新数组内容
  116 + byte[] newbyte = new byte[size];
  117 + // 复制数组的前面部分
  118 + System.arraycopy(bytedata, 0, newbyte, 0, n);
  119 + // 获得数组Append数据元素的位置
  120 + int l = n;
  121 + // 补1操作
  122 + newbyte[l++] = (byte) 0x80;
  123 + // 补0操作
  124 + for (int i = 0; i < zeros; i++) {
  125 + newbyte[l++] = (byte) 0x00;
  126 + }
  127 + // 计算数据长度,补数据长度位共8字节,长整型
  128 + long N = (long) n * 8;
  129 + byte h8 = (byte) (N & 0xFF);
  130 + byte h7 = (byte) ((N >> 8) & 0xFF);
  131 + byte h6 = (byte) ((N >> 16) & 0xFF);
  132 + byte h5 = (byte) ((N >> 24) & 0xFF);
  133 + byte h4 = (byte) ((N >> 32) & 0xFF);
  134 + byte h3 = (byte) ((N >> 40) & 0xFF);
  135 + byte h2 = (byte) ((N >> 48) & 0xFF);
  136 + byte h1 = (byte) (N >> 56);
  137 + newbyte[l++] = h1;
  138 + newbyte[l++] = h2;
  139 + newbyte[l++] = h3;
  140 + newbyte[l++] = h4;
  141 + newbyte[l++] = h5;
  142 + newbyte[l++] = h6;
  143 + newbyte[l++] = h7;
  144 + newbyte[l++] = h8;
  145 + return newbyte;
  146 + }
  147 +
  148 + private int f1(int x, int y, int z) {
  149 + return (x & y) | (~x & z);
  150 + }
  151 +
  152 + private int f2(int x, int y, int z) {
  153 + return x ^ y ^ z;
  154 + }
  155 +
  156 + private int f3(int x, int y, int z) {
  157 + return (x & y) | (x & z) | (y & z);
  158 + }
  159 +
  160 + //
  161 +
  162 + private int f4(int x, int y) {
  163 + return (x << y) | x >>> (32 - y);
  164 + }
  165 +
  166 + /**
  167 + * 单元摘要计算函数
  168 + */
  169 + private void encrypt() {
  170 + for (int i = 16; i <= 79; i++) {
  171 + tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14]
  172 + ^ tmpData[i - 16], 1);
  173 + }
  174 + int[] tmpabcde = new int[5];
  175 + System.arraycopy(digestInt, 0, tmpabcde, 0, tmpabcde.length);
  176 + for (int j = 0; j <= 19; j++) {
  177 + int tmp = f4(tmpabcde[0], 5)
  178 + + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  179 + + tmpData[j] + 0x5a827999;
  180 + tmpabcde[4] = tmpabcde[3];
  181 + tmpabcde[3] = tmpabcde[2];
  182 + tmpabcde[2] = f4(tmpabcde[1], 30);
  183 + tmpabcde[1] = tmpabcde[0];
  184 + tmpabcde[0] = tmp;
  185 + }
  186 + for (int k = 20; k <= 39; k++) {
  187 + int tmp = f4(tmpabcde[0], 5)
  188 + + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  189 + + tmpData[k] + 0x6ed9eba1;
  190 + tmpabcde[4] = tmpabcde[3];
  191 + tmpabcde[3] = tmpabcde[2];
  192 + tmpabcde[2] = f4(tmpabcde[1], 30);
  193 + tmpabcde[1] = tmpabcde[0];
  194 + tmpabcde[0] = tmp;
  195 + }
  196 + for (int l = 40; l <= 59; l++) {
  197 + int tmp = f4(tmpabcde[0], 5)
  198 + + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  199 + + tmpData[l] + 0x8f1bbcdc;
  200 + tmpabcde[4] = tmpabcde[3];
  201 + tmpabcde[3] = tmpabcde[2];
  202 + tmpabcde[2] = f4(tmpabcde[1], 30);
  203 + tmpabcde[1] = tmpabcde[0];
  204 + tmpabcde[0] = tmp;
  205 + }
  206 + for (int m = 60; m <= 79; m++) {
  207 + int tmp = f4(tmpabcde[0], 5)
  208 + + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  209 + + tmpData[m] + 0xca62c1d6;
  210 + tmpabcde[4] = tmpabcde[3];
  211 + tmpabcde[3] = tmpabcde[2];
  212 + tmpabcde[2] = f4(tmpabcde[1], 30);
  213 + tmpabcde[1] = tmpabcde[0];
  214 + tmpabcde[0] = tmp;
  215 + }
  216 + for (int i2 = 0; i2 < tmpabcde.length; i2++) {
  217 + digestInt[i2] = digestInt[i2] + tmpabcde[i2];
  218 + }
  219 + for (int n = 0; n < tmpData.length; n++) {
  220 + tmpData[n] = 0;
  221 + }
  222 + }
  223 +
  224 + /**
  225 + * 4字节数组转换为整数
  226 + *
  227 + * @param bytedata
  228 + * @param i
  229 + * @return
  230 + */
  231 + private int byteArrayToInt(byte[] bytedata, int i) {
  232 + return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16)
  233 + | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff);
  234 + }
  235 +
  236 + /**
  237 + * 整数转换为4字节数组
  238 + *
  239 + * @param intValue
  240 + * @param byteData
  241 + * @param i
  242 + */
  243 + private void intToByteArray(int intValue, byte[] byteData, int i) {
  244 + byteData[i] = (byte) (intValue >>> 24);
  245 + byteData[i + 1] = (byte) (intValue >>> 16);
  246 + byteData[i + 2] = (byte) (intValue >>> 8);
  247 + byteData[i + 3] = (byte) intValue;
  248 + }
  249 +
  250 + /**
  251 + * 计算sha-1摘要,返回相应的字节数组
  252 + *
  253 + * @param byteData
  254 + * @return
  255 + */
  256 + public byte[] getDigestOfBytes(byte[] byteData) {
  257 + process_input_bytes(byteData);
  258 + byte[] digest = new byte[20];
  259 + for (int i = 0; i < digestInt.length; i++) {
  260 + intToByteArray(digestInt[i], digest, i * 4);
  261 + }
  262 + return digest;
  263 + }
  264 +
  265 + /**
  266 + * 计算sha-1摘要,返回相应的十六进制字符串
  267 + *
  268 + * @param byteData
  269 + * @return
  270 + */
  271 + public String getDigestOfString(byte[] byteData) {
  272 + return byteArrayToHexString(getDigestOfBytes(byteData));
  273 + }
  274 +
  275 + /**
  276 + * @param data
  277 + * @return
  278 + */
  279 + public String Digest(String data) {
  280 + return this.getDigestOfString(data.getBytes());
  281 + }
  282 +
  283 + /**
  284 + * @param data
  285 + * @return
  286 + */
  287 + public String Digest(String data, String encode) {
  288 + try {
  289 + return this.getDigestOfString(data.getBytes(encode));
  290 + } catch (UnsupportedEncodingException e) {
  291 + return this.Digest(data);
  292 + }
  293 + }
  294 +}
app/src/main/java/com/cnlive/gundam/main/network/util/SignUtil.java 0 → 100644
  1 +package com.cnlive.gundam.main.network.util;
  2 +
  3 +import android.content.Context;
  4 +import android.util.Log;
  5 +
  6 +import com.cnlive.gundam.main.network.util.SHA1;
  7 +import com.cnlive.libs.util.Config;
  8 +import com.cnlive.libs.util.data.okhttp3.Headers;
  9 +import com.cnlive.libs.util.data.okhttp3.OkHttpClient;
  10 +import com.cnlive.libs.util.data.okhttp3.Request;
  11 +import com.cnlive.libs.util.data.okhttp3.Response;
  12 +
  13 +import java.io.UnsupportedEncodingException;
  14 +import java.net.URLEncoder;
  15 +import java.util.ArrayList;
  16 +import java.util.Collections;
  17 +import java.util.Comparator;
  18 +import java.util.Date;
  19 +import java.util.HashMap;
  20 +import java.util.LinkedHashMap;
  21 +import java.util.List;
  22 +import java.util.Locale;
  23 +import java.util.Map;
  24 +
  25 +/**
  26 + * Created by Lynn on 5/25/2017.
  27 + */
  28 +
  29 +public class SignUtil {
  30 + //时间服务器地址
  31 + private static final String URL_TIME_SERVICE = "https://api.cnlive.com/open/api2/timestamp";
  32 +
  33 + private static final String TAG = "SignUtil";
  34 +
  35 + public static Map<String, String> getSignParamM(Context context, Map<String, String> params) {
  36 + if (context == null || params == null) return new HashMap<>();
  37 + params.put("platform_id", context.getPackageName());
  38 + params.put("timestamp", String.valueOf(getTime() / 1000));
  39 + Map<String, String> map = order(params);
  40 + if (map.containsKey("sign")) {
  41 + map.remove("sign");
  42 + }
  43 + String signValue = SHA1
  44 + .SHA1Digest(mapJoin(map, false).concat("&key=").concat(Config.getSpKey()))
  45 + .toUpperCase(Locale.getDefault());
  46 + map.put("sign", signValue);
  47 + return map;
  48 + }
  49 +
  50 + private static String getSignParam(Context context, Map<String, String> params) {
  51 + if (context == null || params == null) return "";
  52 + params.put("platform_id", context.getPackageName());
  53 + params.put("timestamp", String.valueOf(getTime() / 1000));
  54 +
  55 + String signParam = mapParam(params);
  56 +
  57 + Map<String, String> map = order(params);
  58 +
  59 + if (map.containsKey("sign")) {
  60 + map.remove("sign");
  61 + }
  62 +
  63 + String signValue = SHA1.SHA1Digest(mapJoin(map, false).concat("&key=").concat(Config.getSpKey()))
  64 + .toUpperCase(Locale.getDefault());
  65 + return signParam.concat("&sign=").concat(signValue);
  66 + }
  67 +
  68 + private static long getTime() {
  69 + OkHttpClient okHttpClient = new OkHttpClient();
  70 + try {
  71 + Request request = new Request.Builder().url(URL_TIME_SERVICE).build();
  72 + Response response = okHttpClient.newCall(request).execute();
  73 + Headers headers = response.headers();
  74 +
  75 + Date date = headers.getDate("Date");
  76 + return date == null ? System.currentTimeMillis() : date.getTime();
  77 + } catch (Exception e) {
  78 + e.printStackTrace();
  79 + }
  80 +
  81 + return System.currentTimeMillis();
  82 + }
  83 +
  84 + public static String mapParam(Map<String, String> map) {
  85 + StringBuilder stringBuilder = new StringBuilder();
  86 + for (String key : map.keySet()) {
  87 + stringBuilder.append(key).append("=").append(map.get(key)).append("&");
  88 + }
  89 + if (stringBuilder.length() > 0) {
  90 + stringBuilder.deleteCharAt(stringBuilder.length() - 1);
  91 + }
  92 + return stringBuilder.toString();
  93 + }
  94 +
  95 + private static Map<String, String> order(Map<String, String> map) {
  96 + HashMap<String, String> tempMap = new LinkedHashMap<>();
  97 + List<Map.Entry<String, String>> infoIds = new ArrayList<>(map.entrySet());
  98 +
  99 + Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
  100 + public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
  101 + return o1.getKey().compareTo(o2.getKey());
  102 + }
  103 + });
  104 +
  105 + for (int i = 0; i < infoIds.size(); i++) {
  106 + Map.Entry<String, String> item = infoIds.get(i);
  107 + tempMap.put(item.getKey(), item.getValue());
  108 + }
  109 + return tempMap;
  110 + }
  111 +
  112 + private static String mapJoin(Map<String, String> map, boolean valueUrlencode) {
  113 + StringBuilder stringBuilder = new StringBuilder();
  114 + for (String key : map.keySet()) {
  115 + if (map.get(key) != null && !"".equals(map.get(key))) {
  116 + try {
  117 + stringBuilder.append(key)
  118 + .append("=")
  119 + .append(valueUrlencode ? URLEncoder.encode(map.get(key), "utf-8").replace("+", "%20") : map.get(key))
  120 + .append("&");
  121 + } catch (UnsupportedEncodingException e) {
  122 + Log.e(TAG, "Load:" + e.getMessage(), e);
  123 + }
  124 + }
  125 + }
  126 + if (stringBuilder.length() > 0) {
  127 + stringBuilder.deleteCharAt(stringBuilder.length() - 1);
  128 + }
  129 + return stringBuilder.toString();
  130 + }
  131 +}
app/src/main/java/com/cnlive/gundam/main/ui/activity/MainActivity.java
1 package com.cnlive.gundam.main.ui.activity; 1 package com.cnlive.gundam.main.ui.activity;
2 2
3 -import android.content.Intent;  
4 import android.databinding.DataBindingUtil; 3 import android.databinding.DataBindingUtil;
5 import android.os.Bundle; 4 import android.os.Bundle;
6 import android.support.v7.app.AppCompatActivity; 5 import android.support.v7.app.AppCompatActivity;
@@ -12,7 +11,6 @@ import com.cnlive.gundam.main.ui.fragment.HomeFragment; @@ -12,7 +11,6 @@ import com.cnlive.gundam.main.ui.fragment.HomeFragment;
12 import com.cnlive.gundam.main.ui.fragment.LiveFragment; 11 import com.cnlive.gundam.main.ui.fragment.LiveFragment;
13 import com.cnlive.gundam.main.ui.fragment.UGCListFragment; 12 import com.cnlive.gundam.main.ui.fragment.UGCListFragment;
14 import com.cnlive.gundam.main.ui.widget.FragmentTabHost; 13 import com.cnlive.gundam.main.ui.widget.FragmentTabHost;
15 -import com.cnlive.gundam.stream.ui.activity.StreamActivity;  
16 14
17 import java.util.Arrays; 15 import java.util.Arrays;
18 16
@@ -41,16 +39,14 @@ public class MainActivity extends AppCompatActivity implements FragmentTabHost.O @@ -41,16 +39,14 @@ public class MainActivity extends AppCompatActivity implements FragmentTabHost.O
41 public boolean onSetCurrentTab(String tag) { 39 public boolean onSetCurrentTab(String tag) {
42 switch (tag) { 40 switch (tag) {
43 case "stream": 41 case "stream":
44 - Intent intent = new Intent(this, StreamActivity.class);  
45 - intent.putExtra("activityId", ""+System.currentTimeMillis());  
46 - intent.putExtra("channelId", "androidtest");  
47 - intent.putExtra("channelName", "androidTest");  
48 - intent.putExtra("coverImgUrl", "");  
49 - intent.putExtra("landscape", false);  
50 - startActivity(intent); 42 + onSetStreamTab();
51 return true; 43 return true;
52 } 44 }
53 return false; 45 return false;
54 } 46 }
55 47
  48 + private void onSetStreamTab(){
  49 +
  50 + }
  51 +
56 } 52 }
57 \ No newline at end of file 53 \ No newline at end of file
app/src/main/java/com/cnlive/gundam/main/ui/fragment/HomeFragment.java
1 package com.cnlive.gundam.main.ui.fragment; 1 package com.cnlive.gundam.main.ui.fragment;
2 2
  3 +import android.databinding.DataBindingUtil;
  4 +import android.os.Bundle;
  5 +import android.support.annotation.Nullable;
3 import android.support.v4.app.Fragment; 6 import android.support.v4.app.Fragment;
  7 +import android.support.v4.widget.SwipeRefreshLayout;
  8 +import android.support.v7.widget.LinearLayoutManager;
  9 +import android.view.LayoutInflater;
  10 +import android.view.View;
  11 +import android.view.ViewGroup;
  12 +import android.widget.Toast;
  13 +
  14 +import com.cnlive.gundam.BR;
  15 +import com.cnlive.gundam.R;
  16 +import com.cnlive.gundam.databinding.FragmentActiveListBinding;
  17 +import com.cnlive.gundam.main.model.VideoListProgram;
  18 +import com.cnlive.gundam.main.model.VodListPage;
  19 +import com.cnlive.gundam.main.network.RetrofitUtil;
  20 +import com.cnlive.gundam.main.network.util.SignUtil;
  21 +import com.cnlive.gundam.main.ui.adapter.DataBindingAdapter;
  22 +import com.cnlive.gundam.main.utils.ActivityJumpUtil;
  23 +import com.cnlive.libs.util.Config;
  24 +
  25 +import java.util.HashMap;
  26 +import java.util.Map;
  27 +
  28 +import retrofit2.Call;
  29 +import retrofit2.Callback;
  30 +import retrofit2.Response;
4 31
5 /** 32 /**
6 * Created by xiansong on 2017/6/27. 33 * Created by xiansong on 2017/6/27.
  34 + * 此demo没有实现分页逻辑
7 */ 35 */
8 36
9 -public class HomeFragment extends Fragment {  
10 -} 37 +public class HomeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener,
  38 + DataBindingAdapter.OnAdapterViewClickListener<VideoListProgram>,
  39 + DataBindingAdapter.OnAdapterViewLoadMoreListener, Callback<VodListPage> {
  40 +
  41 + private FragmentActiveListBinding binding;
  42 + private DataBindingAdapter adapter;
  43 +
  44 + @Override
  45 + public void onCreate(Bundle savedInstanceState) {
  46 + super.onCreate(savedInstanceState);
  47 + }
  48 +
  49 + @Override
  50 + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  51 + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_active_list, container, false);
  52 + binding.setListAdapter(adapter = new DataBindingAdapter(getActivity(), R.layout.layout_item_video_list, BR.program));
  53 + adapter.setOnViewClickListener(this);
  54 + adapter.setOnLoadMoreListener(this);
  55 + binding.setLayoutManager(new LinearLayoutManager(getActivity()));
  56 + binding.contentView.setOnRefreshListener(this);
  57 + return binding.getRoot();
  58 + }
  59 +
  60 + @Override
  61 + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  62 + super.onViewCreated(view, savedInstanceState);
  63 + loadData();
  64 + }
  65 +
  66 + private void loadData() {
  67 + Map<String, String> params = new HashMap<>();
  68 + params.put("appId", Config.getAppId());
  69 + params.put("pageNumber", "1");
  70 + params.put("pageSize", "15");
  71 + RetrofitUtil.getApiService().getVodInfoList(SignUtil.getSignParamM(getActivity(), params)).enqueue(this);
  72 + }
  73 +
  74 + @Override
  75 + public void onRefresh() {
  76 + loadData();
  77 + }
  78 +
  79 + @Override
  80 + public void onViewClick(View v, VideoListProgram program) {
  81 + if (v.getId() == R.id.itemLayout) {
  82 + ActivityJumpUtil.jumpByProgramType(getActivity(), program);
  83 + }
  84 + }
  85 +
  86 + @Override
  87 + public void onLoadMore() {
  88 +
  89 + }
  90 +
  91 + @Override
  92 + public void onResponse(Call<VodListPage> call, Response<VodListPage> response) {
  93 + binding.contentView.setRefreshing(false);
  94 + if (response.isSuccessful()) {
  95 + VodListPage model = response.body();
  96 + if (model != null && "0".equals(model.getCode())) {
  97 + if (model.getData() == null) {
  98 + Toast.makeText(getActivity(), getString(R.string.request_null), Toast.LENGTH_LONG).show();
  99 + } else {
  100 + adapter.updateItems(model.getData());
  101 + }
  102 + } else {
  103 + Toast.makeText(getActivity(), getString(R.string.request_error), Toast.LENGTH_LONG).show();
  104 + }
  105 + } else {
  106 + Toast.makeText(getActivity(), getString(R.string.request_error), Toast.LENGTH_LONG).show();
  107 + }
  108 + }
  109 +
  110 + @Override
  111 + public void onFailure(Call<VodListPage> call, Throwable t) {
  112 + binding.contentView.setRefreshing(false);
  113 + Toast.makeText(getActivity(), getString(R.string.request_error), Toast.LENGTH_LONG).show();
  114 + }
  115 +}
11 \ No newline at end of file 116 \ No newline at end of file
app/src/main/java/com/cnlive/gundam/main/ui/fragment/LiveFragment.java
@@ -50,12 +50,12 @@ public class LiveFragment extends Fragment implements DataBindingAdapter.OnAdapt @@ -50,12 +50,12 @@ public class LiveFragment extends Fragment implements DataBindingAdapter.OnAdapt
50 50
51 private void initData() { 51 private void initData() {
52 programs = new ArrayList<>(); 52 programs = new ArrayList<>();
53 - programs.add(new VideoListProgram("liveshow", "LiveShow", "http://yweb0.cnliveimg.com/cnlive/public/150417133551285_693.png", "408481", "live"));  
54 - programs.add(new VideoListProgram("news", "快新闻", "http://yweb1.cnliveimg.com/img/cnlive/160121113653827_867.png", "85697", "live"));  
55 - programs.add(new VideoListProgram("eyule", "e娱乐", "http://yweb2.cnliveimg.com/img/cnlive/160121113659992_585.png", "408480", "live"));  
56 - programs.add(new VideoListProgram("chaotiyu", "潮体育", "http://yweb3.cnliveimg.com/img/cnlive/160121113706887_696.png", "285698", "live"));  
57 - programs.add(new VideoListProgram("xuanhanyu", "炫韩娱", "http://yweb0.cnliveimg.com/cnlive/public/150417133341123_878.png", "408487", "live"));  
58 - programs.add(new VideoListProgram("inyuetai", "in乐台", "http://yweb1.cnliveimg.com/cnlive/public/150417144750615_185.png", "285696", "live")); 53 + programs.add(new VideoListProgram("82_liveshow", "LiveShow", "http://yweb0.cnliveimg.com/cnlive/public/150417133551285_693.png", "408481", "live"));
  54 + programs.add(new VideoListProgram("82_news", "快新闻", "http://yweb1.cnliveimg.com/img/cnlive/160121113653827_867.png", "85697", "live"));
  55 + programs.add(new VideoListProgram("82_eyule", "e娱乐", "http://yweb2.cnliveimg.com/img/cnlive/160121113659992_585.png", "408480", "live"));
  56 + programs.add(new VideoListProgram("82_chaotiyu", "潮体育", "http://yweb3.cnliveimg.com/img/cnlive/160121113706887_696.png", "285698", "live"));
  57 + programs.add(new VideoListProgram("82_xuanhanyu", "炫韩娱", "http://yweb0.cnliveimg.com/cnlive/public/150417133341123_878.png", "408487", "live"));
  58 + programs.add(new VideoListProgram("82_inyuetai", "in乐台", "http://yweb1.cnliveimg.com/cnlive/public/150417144750615_185.png", "285696", "live"));
59 } 59 }
60 60
61 @Override 61 @Override
app/src/main/java/com/cnlive/gundam/main/ui/fragment/UGCListFragment.java
@@ -9,18 +9,34 @@ import android.support.v7.widget.LinearLayoutManager; @@ -9,18 +9,34 @@ import android.support.v7.widget.LinearLayoutManager;
9 import android.view.LayoutInflater; 9 import android.view.LayoutInflater;
10 import android.view.View; 10 import android.view.View;
11 import android.view.ViewGroup; 11 import android.view.ViewGroup;
  12 +import android.widget.Toast;
12 13
13 import com.cnlive.gundam.BR; 14 import com.cnlive.gundam.BR;
14 import com.cnlive.gundam.R; 15 import com.cnlive.gundam.R;
15 import com.cnlive.gundam.databinding.FragmentActiveListBinding; 16 import com.cnlive.gundam.databinding.FragmentActiveListBinding;
16 import com.cnlive.gundam.main.model.ActiveInfo; 17 import com.cnlive.gundam.main.model.ActiveInfo;
  18 +import com.cnlive.gundam.main.model.ActiveListModel;
  19 +import com.cnlive.gundam.main.network.RetrofitUtil;
  20 +import com.cnlive.gundam.main.network.util.SignUtil;
17 import com.cnlive.gundam.main.ui.adapter.DataBindingAdapter; 21 import com.cnlive.gundam.main.ui.adapter.DataBindingAdapter;
  22 +import com.cnlive.gundam.main.utils.ActivityJumpUtil;
  23 +import com.cnlive.libs.util.Config;
  24 +
  25 +import java.util.HashMap;
  26 +import java.util.Map;
  27 +
  28 +import retrofit2.Call;
  29 +import retrofit2.Callback;
  30 +import retrofit2.Response;
18 31
19 /** 32 /**
20 * Created by xiansong on 2017/6/27. 33 * Created by xiansong on 2017/6/27.
  34 + * 此 demo 没有实现分页加载
21 */ 35 */
22 36
23 -public class UGCListFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, DataBindingAdapter.OnAdapterViewClickListener<ActiveInfo>, DataBindingAdapter.OnAdapterViewLoadMoreListener { 37 +public class UGCListFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener,
  38 + DataBindingAdapter.OnAdapterViewClickListener<ActiveInfo>,
  39 + DataBindingAdapter.OnAdapterViewLoadMoreListener, Callback<ActiveListModel> {
24 40
25 private FragmentActiveListBinding binding; 41 private FragmentActiveListBinding binding;
26 private DataBindingAdapter adapter; 42 private DataBindingAdapter adapter;
@@ -33,7 +49,7 @@ public class UGCListFragment extends Fragment implements SwipeRefreshLayout.OnRe @@ -33,7 +49,7 @@ public class UGCListFragment extends Fragment implements SwipeRefreshLayout.OnRe
33 @Override 49 @Override
34 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 50 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
35 binding = DataBindingUtil.inflate(inflater, R.layout.fragment_active_list, container, false); 51 binding = DataBindingUtil.inflate(inflater, R.layout.fragment_active_list, container, false);
36 - binding.setListAdapter(adapter = new DataBindingAdapter(getActivity(), R.layout.layout_item_video_list, BR.program)); 52 + binding.setListAdapter(adapter = new DataBindingAdapter(getActivity(), R.layout.layout_item_active_video_list, BR.activeInfo));
37 adapter.setOnViewClickListener(this); 53 adapter.setOnViewClickListener(this);
38 adapter.setOnLoadMoreListener(this); 54 adapter.setOnLoadMoreListener(this);
39 binding.setLayoutManager(new LinearLayoutManager(getActivity())); 55 binding.setLayoutManager(new LinearLayoutManager(getActivity()));
@@ -48,22 +64,55 @@ public class UGCListFragment extends Fragment implements SwipeRefreshLayout.OnRe @@ -48,22 +64,55 @@ public class UGCListFragment extends Fragment implements SwipeRefreshLayout.OnRe
48 } 64 }
49 65
50 private void loadData() { 66 private void loadData() {
51 - 67 + Map<String, String> params = new HashMap<>();
  68 + //TODO 传多个播放状态
  69 + params.put("appId", Config.getAppId());
  70 + params.put("activityStatus", "2");
  71 + params.put("pageNo", "1");
  72 + params.put("pageSize", "15");
  73 + RetrofitUtil.getApiService().getSpActivityList(SignUtil.getSignParamM(getActivity(), params)).enqueue(this);
52 } 74 }
53 75
54 @Override 76 @Override
55 public void onRefresh() { 77 public void onRefresh() {
56 - 78 + loadData();
57 } 79 }
58 80
59 @Override 81 @Override
60 public void onViewClick(View v, ActiveInfo program) { 82 public void onViewClick(View v, ActiveInfo program) {
61 - 83 + if (v.getId() == R.id.itemLayout) {
  84 + ActivityJumpUtil.jumpByProgramType(getActivity(), program);
  85 + }
62 } 86 }
63 87
64 @Override 88 @Override
65 public void onLoadMore() { 89 public void onLoadMore() {
66 90
67 } 91 }
  92 +
  93 + @Override
  94 + public void onResponse(Call<ActiveListModel> call, Response<ActiveListModel> response) {
  95 + binding.contentView.setRefreshing(false);
  96 + if (response.isSuccessful()) {
  97 + ActiveListModel model = response.body();
  98 + if (model != null && "0".equals(model.getCode())) {
  99 + if (model.getData() == null) {
  100 + Toast.makeText(getActivity(), getString(R.string.request_null), Toast.LENGTH_LONG).show();
  101 + } else {
  102 + adapter.updateItems(model.getData().getActivityList());
  103 + }
  104 + } else {
  105 + Toast.makeText(getActivity(), getString(R.string.request_error), Toast.LENGTH_LONG).show();
  106 + }
  107 + } else {
  108 + Toast.makeText(getActivity(), getString(R.string.request_error), Toast.LENGTH_LONG).show();
  109 + }
  110 + }
  111 +
  112 + @Override
  113 + public void onFailure(Call<ActiveListModel> call, Throwable t) {
  114 + binding.contentView.setRefreshing(false);
  115 + Toast.makeText(getActivity(), getString(R.string.request_error), Toast.LENGTH_LONG).show();
  116 + }
68 } 117 }
69 118
app/src/main/java/com/cnlive/gundam/main/utils/ActivityJumpUtil.java
1 package com.cnlive.gundam.main.utils; 1 package com.cnlive.gundam.main.utils;
2 2
3 -import android.app.Activity;  
4 import android.content.Context; 3 import android.content.Context;
5 import android.content.Intent; 4 import android.content.Intent;
  5 +import android.widget.Toast;
6 6
  7 +import com.cnlive.gundam.R;
  8 +import com.cnlive.gundam.main.model.ActiveInfo;
  9 +import com.cnlive.gundam.main.model.ActivePlayInfo;
7 import com.cnlive.gundam.main.model.VideoListProgram; 10 import com.cnlive.gundam.main.model.VideoListProgram;
  11 +import com.cnlive.gundam.main.network.RetrofitUtil;
  12 +import com.cnlive.gundam.main.network.util.SignUtil;
8 import com.cnlive.gundam.video.activity.PlayerActivity; 13 import com.cnlive.gundam.video.activity.PlayerActivity;
  14 +import com.cnlive.gundam.video.view.VideoView;
  15 +import com.cnlive.libs.util.Config;
  16 +
  17 +import java.util.HashMap;
  18 +import java.util.Map;
  19 +
  20 +import retrofit2.Call;
  21 +import retrofit2.Callback;
  22 +import retrofit2.Response;
9 23
10 /** 24 /**
11 * Created by Lynn on 5/27/2017. 25 * Created by Lynn on 5/27/2017.
@@ -13,70 +27,43 @@ import com.cnlive.gundam.video.activity.PlayerActivity; @@ -13,70 +27,43 @@ import com.cnlive.gundam.video.activity.PlayerActivity;
13 27
14 public class ActivityJumpUtil { 28 public class ActivityJumpUtil {
15 29
16 -// //活动视频页面跳转  
17 -// public static void jumpByProgramType(final Context context, final VideoListPage.Program program) {  
18 -// if (context == null || program == null)  
19 -// return;  
20 -//// intentByStatus(context, program);  
21 -// ApiServiceUtil.getActivePlayInfo(context, program.getActivityId()).subscribe(new com.cnlive.granzon.data.network.network.Subscriber<ActivePlayInfo>() {  
22 -// @Override  
23 -// public void onCompleted(ActivePlayInfo data) {  
24 -// program.setIsHorizontalScreen(data.getData().getIsHorizontalScreen());  
25 -// program.setActivityId(data.getData().getActivityId());  
26 -// program.setChannelId(data.getData().getChannelId());  
27 -// program.setRates(data.getData().getRates());  
28 -// program.setActivityName(data.getData().getActivityName());  
29 -// intentByStatus(context, program);  
30 -// }  
31 -//  
32 -// @Override  
33 -// public void onError(String code, String message) {  
34 -// intentByStatus(context, program);  
35 -// }  
36 -// });  
37 -//  
38 -//  
39 -// }  
40 -//  
41 -// private static void intentByStatus(Context context, VideoListPage.Program program) {  
42 -// switch (program.getActivityStatus()) {  
43 -// case 0:  
44 -// case 3:  
45 -// case 4:  
46 -// if (context instanceof Activity) {  
47 -// Intent intentVod = new Intent(context, PlayerActivity.class);  
48 -// VideoListProgram videoListProgram = VideoListProgram.toVideoListProgram(program, "ugcVod");  
49 -// intentVod.putExtra("program", videoListProgram);  
50 -// intentVod.putExtra("screenDirect", program.getIsHorizontalScreen() + "");  
51 -// context.startActivity(intentVod);  
52 -// } else {  
53 -// Intent intentVod = new Intent(context, PlayerActivity.class);  
54 -// VideoListProgram videoListProgram = VideoListProgram.toVideoListProgram(program, "ugcVod");  
55 -// intentVod.putExtra("program", videoListProgram);  
56 -// intentVod.putExtra("screenDirect", program.getIsHorizontalScreen() + "");  
57 -// intentVod.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
58 -// context.startActivity(intentVod);  
59 -// }  
60 -// break;  
61 -// case -2:  
62 -// case 1:  
63 -// if (context instanceof Activity) {  
64 -// Intent intentLive = new Intent(context, PlayerActivity.class);  
65 -// VideoListProgram videoListProgram = VideoListProgram.toVideoListProgram(program, "ugcLive");  
66 -// intentLive.putExtra("program", videoListProgram);  
67 -// intentLive.putExtra("screenDirect", program.getIsHorizontalScreen() + "");  
68 -// context.startActivity(intentLive);  
69 -// } else {  
70 -// Intent intentLive = new Intent(context, PlayerActivity.class);  
71 -// VideoListProgram videoListProgram = VideoListProgram.toVideoListProgram(program, "ugcLive");  
72 -// intentLive.putExtra("program", videoListProgram);  
73 -// intentLive.putExtra("screenDirect", program.getIsHorizontalScreen() + "");  
74 -// intentLive.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
75 -// context.startActivity(intentLive);  
76 -// }  
77 -// break;  
78 -// }  
79 -// } 30 + //活动视频页面跳转
  31 + public static void jumpByProgramType(final Context context, ActiveInfo activeInfo) {
  32 + if (context == null || activeInfo == null)
  33 + return;
  34 + Map<String, String> params = new HashMap<>();
  35 + params.put("appId", Config.getAppId());
  36 + params.put("activityId", activeInfo.getActivityId());
  37 + RetrofitUtil.getApiService().getActivityPlayInfo(SignUtil.getSignParamM(context, params)).enqueue(new Callback<ActivePlayInfo>() {
  38 + @Override
  39 + public void onResponse(Call<ActivePlayInfo> call, Response<ActivePlayInfo> response) {
  40 + if (response.isSuccessful()) {
  41 + ActivePlayInfo info = response.body();
  42 + if (info != null && "0".equals(info.getCode())) {
  43 + jumpByStatus(context, info.getData());
  44 + } else {
  45 + Toast.makeText(context, context.getString(R.string.request_state_error), Toast.LENGTH_LONG).show();
  46 + }
  47 + }
  48 + }
  49 +
  50 + @Override
  51 + public void onFailure(Call<ActivePlayInfo> call, Throwable t) {
  52 + Toast.makeText(context, context.getString(R.string.request_state_error), Toast.LENGTH_LONG).show();
  53 + }
  54 + });
  55 + }
  56 +
  57 + private static void jumpByStatus(Context context, ActivePlayInfo.ActiveModel model) {
  58 + if (model == null) return;
  59 + if (model.getActivityStatus() == 1) {//直播中
  60 + jumpByProgramType(context, new VideoListProgram(model.getChannelId(), model.getActivityName(), model.getCoverImgUrl(), model.getRates(), VideoView.TYPE_UGC_LIVE));
  61 + } else if (model.getActivityStatus() == 3) {//已结束
  62 + jumpByProgramType(context, new VideoListProgram(model.getActivityId(), model.getActivityName(), model.getCoverImgUrl(), model.getActivityName(), model.getRates(), VideoView.TYPE_UGC_VOD));
  63 + } else {
  64 + Toast.makeText(context, context.getString(R.string.request_state_play_error), Toast.LENGTH_LONG).show();
  65 + }
  66 + }
80 67
81 //视频页面跳转 68 //视频页面跳转
82 public static void jumpByProgramType(final Context context, final VideoListProgram program) { 69 public static void jumpByProgramType(final Context context, final VideoListProgram program) {
app/src/main/java/com/cnlive/gundam/stream/ui/activity/StreamActivity.java
@@ -2,7 +2,9 @@ package com.cnlive.gundam.stream.ui.activity; @@ -2,7 +2,9 @@ package com.cnlive.gundam.stream.ui.activity;
2 2
3 import android.app.AlertDialog; 3 import android.app.AlertDialog;
4 import android.app.Dialog; 4 import android.app.Dialog;
  5 +import android.content.Context;
5 import android.content.DialogInterface; 6 import android.content.DialogInterface;
  7 +import android.content.Intent;
6 import android.databinding.DataBindingUtil; 8 import android.databinding.DataBindingUtil;
7 import android.os.Bundle; 9 import android.os.Bundle;
8 import android.os.Handler; 10 import android.os.Handler;
@@ -70,6 +72,16 @@ public class StreamActivity extends BaseStreamActivity implements ChatConnect.Ch @@ -70,6 +72,16 @@ public class StreamActivity extends BaseStreamActivity implements ChatConnect.Ch
70 private TimerUtil timerUtil; 72 private TimerUtil timerUtil;
71 private String extensions; 73 private String extensions;
72 74
  75 + public static void start(Context context, String activityId, String channelId, String channelName, String coverImgUrl, boolean landscage) {
  76 + Intent intent = new Intent(context, StreamActivity.class);
  77 + intent.putExtra("activityId", activityId);
  78 + intent.putExtra("channelId", channelId);
  79 + intent.putExtra("channelName", channelName);
  80 + intent.putExtra("coverImgUrl", coverImgUrl);
  81 + intent.putExtra("landscape", landscage);
  82 + context.startActivity(intent);
  83 + }
  84 +
73 @Override 85 @Override
74 protected void onCreate(Bundle savedInstanceState) { 86 protected void onCreate(Bundle savedInstanceState) {
75 super.onCreate(savedInstanceState); 87 super.onCreate(savedInstanceState);
app/src/main/java/com/cnlive/gundam/user/util/FileUtils.java
@@ -10,7 +10,6 @@ import android.text.format.Formatter; @@ -10,7 +10,6 @@ import android.text.format.Formatter;
10 10
11 import com.cnlive.libs.util.SharedPreferencesHelper; 11 import com.cnlive.libs.util.SharedPreferencesHelper;
12 12
13 -import org.jivesoftware.smack.util.StringUtils;  
14 13
15 import java.io.File; 14 import java.io.File;
16 import java.io.IOException; 15 import java.io.IOException;
@@ -186,7 +185,7 @@ public class FileUtils { @@ -186,7 +185,7 @@ public class FileUtils {
186 } 185 }
187 186
188 public static String getUrlFileExtensionName(String url) { 187 public static String getUrlFileExtensionName(String url) {
189 - if(StringUtils.isEmpty(url)) return ""; 188 + if(TextUtils.isEmpty(url)) return "";
190 int slashIndex = url.lastIndexOf('/'); 189 int slashIndex = url.lastIndexOf('/');
191 String filenameWithoutExtension; 190 String filenameWithoutExtension;
192 filenameWithoutExtension = url.substring(slashIndex + 1); 191 filenameWithoutExtension = url.substring(slashIndex + 1);
@@ -206,7 +205,7 @@ public class FileUtils { @@ -206,7 +205,7 @@ public class FileUtils {
206 } 205 }
207 206
208 public static String getUrlExtension(String url) { 207 public static String getUrlExtension(String url) {
209 - if (!StringUtils.isEmpty(url)) { 208 + if (!TextUtils.isEmpty(url)) {
210 int i = url.lastIndexOf('.'); 209 int i = url.lastIndexOf('.');
211 if (i > 0 && i < url.length() - 1) { 210 if (i > 0 && i < url.length() - 1) {
212 return url.substring(i + 1).toLowerCase(Locale.getDefault()); 211 return url.substring(i + 1).toLowerCase(Locale.getDefault());
app/src/main/java/com/cnlive/gundam/user/util/ToastUtil.java
1 package com.cnlive.gundam.user.util; 1 package com.cnlive.gundam.user.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
  4 +import android.text.TextUtils;
4 import android.view.LayoutInflater; 5 import android.view.LayoutInflater;
5 import android.view.View; 6 import android.view.View;
6 import android.widget.ImageView; 7 import android.widget.ImageView;
@@ -9,7 +10,6 @@ import android.widget.Toast; @@ -9,7 +10,6 @@ import android.widget.Toast;
9 10
10 import com.cnlive.gundam.R; 11 import com.cnlive.gundam.R;
11 12
12 -import org.jivesoftware.smack.util.StringUtils;  
13 13
14 14
15 /** 15 /**
@@ -32,7 +32,7 @@ public class ToastUtil { @@ -32,7 +32,7 @@ public class ToastUtil {
32 // if (!ShockwaveApplication.appOnline) 32 // if (!ShockwaveApplication.appOnline)
33 // return; 33 // return;
34 hide(); 34 hide();
35 - if (null == context || StringUtils.isEmpty(msg)) 35 + if (null == context || TextUtils.isEmpty(msg))
36 return null; 36 return null;
37 if (back_pressed + 2000 < System.currentTimeMillis() || !show_msg.equals(msg)) { 37 if (back_pressed + 2000 < System.currentTimeMillis() || !show_msg.equals(msg)) {
38 hideToast(); 38 hideToast();
app/src/main/java/com/cnlive/gundam/video/activity/PlayerActivity.java
@@ -51,7 +51,7 @@ public class PlayerActivity extends AppCompatActivity { @@ -51,7 +51,7 @@ public class PlayerActivity extends AppCompatActivity {
51 case "live": 51 case "live":
52 fragment = PlayerLiveFragment.newInstance(program); 52 fragment = PlayerLiveFragment.newInstance(program);
53 break; 53 break;
54 - case "program": 54 + case "vod":
55 fragment = PlayerVodFragment.newInstance(program); 55 fragment = PlayerVodFragment.newInstance(program);
56 break; 56 break;
57 case "ugcLive": 57 case "ugcLive":
app/src/main/java/com/cnlive/gundam/video/view/VideoView.java
@@ -429,7 +429,7 @@ public class VideoView extends BaseVideoView implements PlayerTouchView.VideoTou @@ -429,7 +429,7 @@ public class VideoView extends BaseVideoView implements PlayerTouchView.VideoTou
429 public void onCompletion(IMediaPlayer iMediaPlayer) { 429 public void onCompletion(IMediaPlayer iMediaPlayer) {
430 super.onCompletion(iMediaPlayer); 430 super.onCompletion(iMediaPlayer);
431 //非因为异常导致的结束 431 //非因为异常导致的结束
432 - if (!isPlayerError) { 432 + if (!isPlayerError && !isLive) {
433 binding.infoView.show(PlayerInfoView.SHOW_END); 433 binding.infoView.show(PlayerInfoView.SHOW_END);
434 } 434 }
435 } 435 }
app/src/main/res/drawable-hdpi/ic_meiyan.png 0 → 100644

4.49 KB

app/src/main/res/drawable-hdpi/ic_meiyan_on.png 0 → 100644

5.06 KB

app/src/main/res/drawable-hdpi/ic_meiyan_on_sel.png 0 → 100644

4.42 KB

app/src/main/res/drawable-hdpi/ic_meiyan_sel.png 0 → 100644

4.09 KB

app/src/main/res/drawable-mdpi/ic_meiyan.png 0 → 100644

2.45 KB

app/src/main/res/drawable-mdpi/ic_meiyan_on.png 0 → 100644

2.8 KB

app/src/main/res/drawable-mdpi/ic_meiyan_on_sel.png 0 → 100644

2.45 KB

app/src/main/res/drawable-mdpi/ic_meiyan_sel.png 0 → 100644

2.26 KB

app/src/main/res/drawable-xhdpi/ic_meiyan.png 0 → 100644

6.04 KB

app/src/main/res/drawable-xhdpi/ic_meiyan_on.png 0 → 100644

6.82 KB

app/src/main/res/drawable-xhdpi/ic_meiyan_on_sel.png 0 → 100644

6.03 KB

app/src/main/res/drawable-xhdpi/ic_meiyan_sel.png 0 → 100644

5.55 KB

app/src/main/res/drawable-xxhdpi/ic_meiyan.png 0 → 100644

11.1 KB

app/src/main/res/drawable-xxhdpi/ic_meiyan_on.png 0 → 100644

12.5 KB

app/src/main/res/drawable-xxhdpi/ic_meiyan_on_sel.png 0 → 100644

11.1 KB

app/src/main/res/drawable-xxhdpi/ic_meiyan_sel.png 0 → 100644

10.1 KB

app/src/main/res/drawable-xxhdpi/icon_record_meiyan_off.png deleted 100644 → 0

4.48 KB

app/src/main/res/drawable-xxhdpi/icon_record_meiyan_on.png deleted 100644 → 0

6.14 KB

app/src/main/res/drawable-xxxhdpi/ic_meiyan.png 0 → 100644

15.7 KB

app/src/main/res/drawable-xxxhdpi/ic_meiyan_on.png 0 → 100644

17.7 KB

app/src/main/res/drawable-xxxhdpi/ic_meiyan_on_sel.png 0 → 100644

15.8 KB

app/src/main/res/drawable-xxxhdpi/ic_meiyan_sel.png 0 → 100644

14.4 KB

app/src/main/res/drawable/icon_record_meiyan.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<selector xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <item android:drawable="@drawable/ic_meiyan_sel" android:state_pressed="true" />
  4 + <item android:drawable="@drawable/ic_meiyan" android:state_pressed="false" />
  5 +</selector>
0 \ No newline at end of file 6 \ No newline at end of file
app/src/main/res/drawable/icon_record_meiyan_on.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<selector xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <item android:drawable="@drawable/ic_meiyan_on_sel" android:state_pressed="true" />
  4 + <item android:drawable="@drawable/ic_meiyan_on" android:state_pressed="false" />
  5 +</selector>
0 \ No newline at end of file 6 \ No newline at end of file
app/src/main/res/layout/activity_stream_portrait.xml
@@ -162,7 +162,7 @@ @@ -162,7 +162,7 @@
162 android:onClick="onClick" 162 android:onClick="onClick"
163 android:padding="5dp" 163 android:padding="5dp"
164 android:scaleType="fitCenter" 164 android:scaleType="fitCenter"
165 - android:src="@{isShow.beautifulBtn ? @drawable/icon_record_meiyan_on : @drawable/icon_record_meiyan_off}" /> 165 + android:src="@{isShow.beautifulBtn ? @drawable/icon_record_meiyan_on : @drawable/icon_record_meiyan}" />
166 166
167 <ImageButton 167 <ImageButton
168 android:id="@+id/btn_flip" 168 android:id="@+id/btn_flip"
app/src/main/res/layout/layout_item_active_video_list.xml
@@ -4,16 +4,16 @@ @@ -4,16 +4,16 @@
4 4
5 <data> 5 <data>
6 6
7 - <import type="com.cnlive.gundam.main.model.VideoListProgram" /> 7 + <import type="com.cnlive.gundam.main.model.ActiveInfo" />
8 <import type="com.cnlive.gundam.main.ui.adapter.DataBindingAdapter.OnAdapterViewClickListener"/> 8 <import type="com.cnlive.gundam.main.ui.adapter.DataBindingAdapter.OnAdapterViewClickListener"/>
9 9
10 <variable 10 <variable
11 - name="program"  
12 - type="VideoListProgram" /> 11 + name="activeInfo"
  12 + type="ActiveInfo" />
13 13
14 <variable 14 <variable
15 name="viewClickListner" 15 name="viewClickListner"
16 - type="OnAdapterViewClickListener&lt;VideoListProgram>"/> 16 + type="OnAdapterViewClickListener&lt;ActiveInfo>"/>
17 17
18 </data> 18 </data>
19 19
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 android:id="@+id/itemLayout" 21 android:id="@+id/itemLayout"
22 android:layout_width="match_parent" 22 android:layout_width="match_parent"
23 android:layout_height="wrap_content" 23 android:layout_height="wrap_content"
24 - android:onClick="@{(view)->viewClickListner.onViewClick(view,program)}"> 24 + android:onClick="@{(view)->viewClickListner.onViewClick(view,activeInfo)}">
25 25
26 <ImageView 26 <ImageView
27 android:id="@+id/image" 27 android:id="@+id/image"
@@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
29 android:layout_height="200dp" 29 android:layout_height="200dp"
30 android:scaleType="centerCrop" 30 android:scaleType="centerCrop"
31 app:error="@{@drawable/image_error}" 31 app:error="@{@drawable/image_error}"
32 - app:imageUrl="@{program.getImg()}" /> 32 + app:imageUrl="@{activeInfo.getCoverImgUrl()}" />
33 33
34 <TextView 34 <TextView
35 android:id="@+id/title" 35 android:id="@+id/title"
@@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
37 android:layout_height="wrap_content" 37 android:layout_height="wrap_content"
38 android:layout_below="@+id/image" 38 android:layout_below="@+id/image"
39 android:padding="10dp" 39 android:padding="10dp"
40 - android:text="@{program.getTitle()}" 40 + android:text="@{activeInfo.getActivityName()}"
41 android:textColor="@android:color/black" 41 android:textColor="@android:color/black"
42 android:textSize="16sp"/> 42 android:textSize="16sp"/>
43 43
app/src/main/res/values/colors.xml
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 <color name="colorPrimaryDark">#303F9F</color> 4 <color name="colorPrimaryDark">#303F9F</color>
5 <color name="colorAccent">#FF4081</color> 5 <color name="colorAccent">#FF4081</color>
6 6
7 - <color name="list_divider">#9e9e9e</color> 7 + <color name="list_divider">#dedbdb</color>
8 8
9 <color name="rate_sel">#ff0000</color> 9 <color name="rate_sel">#ff0000</color>
10 <color name="rate_nor">#ffffff</color> 10 <color name="rate_nor">#ffffff</color>
app/src/main/res/values/strings.xml
@@ -31,4 +31,76 @@ @@ -31,4 +31,76 @@
31 <string name="loaded_rate_last">""</string> 31 <string name="loaded_rate_last">""</string>
32 <string name="loaded_rate_error_pre">提醒您切换</string> 32 <string name="loaded_rate_error_pre">提醒您切换</string>
33 <string name="loaded_rate_error_last">失败,请重试</string> 33 <string name="loaded_rate_error_last">失败,请重试</string>
  34 +
  35 + <string name="request_error">获取数据失败</string>
  36 + <string name="request_null">暂无数据</string>
  37 + <string name="request_state_error">获取活动状态失败</string>
  38 + <string name="request_state_play_error">此活动状态无法播放</string>
  39 +
  40 +
  41 + <string name="net_connect_toast">"你好像掉线了"</string>
  42 +
  43 + //我的
  44 + <string name="main_tab_config">我的</string>
  45 + <string name="click_login">点击登录</string>
  46 + <string name="login_china_coin">登录就送中国币哟</string>
  47 + <string name="my_config_money_desc">中国币、兑换码、金额</string>
  48 + <string name="logout">注销</string>
  49 +
  50 + //登录页面
  51 + <string name="user_login_account">账号:</string>
  52 + <string name="user_login_account_hint">Email/手机号码</string>
  53 + <string name="user_login_code">密码:</string>
  54 + <string name="user_login_code_hint">6&#8211;20位字母或数字</string>
  55 + <string name="user_login_recall_code">忘记密码?</string>
  56 + <string name="string_fast_access">短信验证登录</string>
  57 + <string name="user_login">登录</string>
  58 + <string name="user_login_third_part_login">第三方账号登录</string>
  59 + <string name="third_login_sina">微博</string>
  60 + <string name="third_login_qq">QQ</string>
  61 + <string name="third_login_weixin">微信</string>
  62 +
  63 + //注册页面
  64 + <string name="register_mobile_hint">请输入您的手机号</string>
  65 + <string name="getmobile_identify_code">获取验证码</string>
  66 + <string name="register_mobile_keycode_hint">请输入您收到的验证码</string>
  67 + <string name="register_password_hint">请设置密码:6&#8211;20位字母或数字</string>
  68 + <string name="register_show_password">显示密码</string>
  69 + <string name="register_and_agree">我已阅读并同意</string>
  70 + <string name="register_btn">注册</string>
  71 +
  72 + //找回密码页面
  73 + <string name="find_password_btn">找回密码</string>
  74 + <string name="find_password_hint">请确认密码:6&#8211;20位字母或数字</string>
  75 + <string name="save_btn">保存</string>
  76 +
  77 + //昵称修改页面
  78 + <string name="user_input_nickname">请输入昵称</string>
  79 +
  80 + //手机号修改页面
  81 + <string name="register_mobile">手机号:</string>
  82 + <string name="user_personal_telephone_hint">手机号码</string>
  83 + <string name="register_mobile_keycode">验证码:</string>
  84 + <string name="hint_6_numbers_code">6位数字验证码</string>
  85 +
  86 + //邮箱修改页面
  87 + <string name="email_notify">修改后,您输入的邮箱将会收到确认邮件,请按邮件中的说明去完成验证,谢谢!</string>
  88 +
  89 + //关于我们页面
  90 + <string name="about_us_visit">访问视讯中国官网</string>
  91 + <string name="about_us_call_phone">拨打客服电话</string>
  92 + <string name="about_us_disclaimer">免责声明</string>
  93 + <string name="about_us_company_name">北京中投视讯文化传媒股份有限公司</string>
  94 +
  95 + //分享
  96 + <string name="toast_msg_share_success">分享成功!</string>
  97 + <string name="toast_msg_share_fail">分享失败,请再试一次</string>
  98 + <string name="toast_msg_share_cancel">取消分享</string>
  99 + <string name="share_program_download_targetUrl"> http://www.cnlive.com/web/guide.jsp</string>
  100 +
  101 + //AccountManager用户管理
  102 + <string name="ACCOUNT_TYPE">com.cnlive.libs.AccountType</string>
  103 + <string name="ACCOUNT_LABEL">@string/app_name</string>
  104 +
  105 + <string name="verified_url" formatted="false">https://mobile.cnlive.com/CnliveMobile/web/review/review.jsp?sid=%s&amp;plat=a&amp;appId=%s </string>
34 </resources> 106 </resources>