├── .gitignore
├── README.md
├── TopsTVPlayer.iml
├── app
├── app.iml
├── build.gradle
├── libs
│ ├── core.jar
│ └── universal-image-loader-1.9.3.jar
├── lint.xml
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── yuantops
│ │ └── tvplayer
│ │ ├── adapter
│ │ └── ListviewAdapter.java
│ │ ├── player
│ │ ├── VideoPlayer.java
│ │ ├── VideoPlayer_native.java
│ │ └── VideoPlayer_vitamio.java
│ │ ├── ui
│ │ ├── LiveListFragment.java
│ │ ├── MainActivity.java
│ │ ├── VODListFragment.java
│ │ ├── VideoPlayActivity.java
│ │ └── WebAPIServerActivity.java
│ │ └── util
│ │ ├── StringUtils.java
│ │ ├── UIRobot.java
│ │ └── VolleySingleton.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ ├── ic_launcher.png
│ ├── ic_seekbar_thumb.png
│ ├── pause.png
│ ├── play.png
│ ├── ratingbar_full.xml
│ ├── star_selected.png
│ ├── star_unselect.png
│ └── vlc.jpg
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ ├── activity_main.xml
│ ├── activity_player.xml
│ ├── activity_videoplay.xml
│ ├── activity_web_server.xml
│ ├── fragment_live.xml
│ ├── fragment_vod.xml
│ └── view_video.xml
│ ├── menu
│ └── main.xml
│ ├── values-sw600dp
│ └── dimens.xml
│ ├── values-sw720dp-land
│ └── dimens.xml
│ ├── values-v11
│ └── styles.xml
│ ├── values-v14
│ └── styles.xml
│ └── values
│ ├── dimens.xml
│ ├── ratingbar_style.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── project.properties
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 |
19 | # Local configuration file (sdk path, etc)
20 | local.properties
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Log Files
26 | *.log
27 |
28 | # idea settings
29 | .idea/
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | TopsTVPlayer
2 | ============
3 |
4 | Android video player which plays real-time live video stream and on demand video stream, supporting HTTP/RTSP protocol.
5 |
6 | ##Notes:
7 |
8 | - (2015.09.13) Update: Basic features have finished developing in this version.
9 |
10 | - This is the **Android client part** of a complete online video serving system. This player fetches JSON-format data from the web server, parsing it and then playing the vod/real-time video stream from the retrieved stream url. It does NOT support playing local videos.
11 |
12 | - (2016.04.20) Update: web server for this project can be found at [TopsAPIServer](https://github.com/yuantops/TopsAPIServer). **Server part** of this online video system includes: a media server (Helix), a web api server (Tomcat) and a database server (MySQL). Deployments of all those servers are requisites to make this app work.
13 |
14 | - Deployment guides (Chinese version) of the server can be found at [this link](http://blog.yuantops.com/tech/write-your-own-vod-system).
15 |
16 | ##Projects/Libraries used by this project:
17 | - [ActionbarSherlock](http://actionbarsherlock.com/)
18 | - [Vitamio SDK](https://www.vitamio.org/en/)
19 | - [Android Volley](https://github.com/mcxiaoke/android-volley)
20 |
--------------------------------------------------------------------------------
/TopsTVPlayer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 19
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.yuantops.tvplayer"
9 | minSdkVersion 14
10 | targetSdkVersion 19
11 | }
12 |
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
23 | compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
24 | compile 'com.android.support:support-v4:19.0.+'
25 | compile 'me.neavo:vitamio:4.2.2'
26 | compile 'com.google.zxing:core:2.0'
27 | compile 'com.mcxiaoke.volley:library:1.0.18'
28 |
29 | testCompile 'junit:junit:4.12'
30 | }
31 |
--------------------------------------------------------------------------------
/app/libs/core.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/libs/core.jar
--------------------------------------------------------------------------------
/app/libs/universal-image-loader-1.9.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/libs/universal-image-loader-1.9.3.jar
--------------------------------------------------------------------------------
/app/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/adapter/ListviewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.TextView;
9 | import com.yuantops.tvplayer.R;
10 | import org.json.JSONArray;
11 | import org.json.JSONException;
12 | import org.json.JSONObject;
13 |
14 | /**
15 | * Created by yuan on 9/5/15.
16 | */
17 | public class ListviewAdapter extends BaseAdapter {
18 | private static final String TAG = ListviewAdapter.class.getSimpleName();
19 |
20 | private Context mCtx;
21 | private JSONArray mJsonArr;
22 |
23 | public ListviewAdapter(Context context, JSONArray jsonArray) {
24 | mCtx = context;
25 | mJsonArr = jsonArray;
26 | }
27 |
28 | public int getCount() {
29 | return mJsonArr.length();
30 | }
31 |
32 | @Override
33 | public Object getItem(int position) {
34 | JSONObject jsonObject = null;
35 | try {
36 | jsonObject = (JSONObject) mJsonArr.get(position);
37 | } catch (JSONException e) {
38 | e.printStackTrace();
39 | }
40 | return jsonObject;
41 | }
42 |
43 | @Override
44 | public long getItemId(int position) {
45 | return position;
46 | }
47 |
48 | @Override
49 | public View getView(int position, View convertView, ViewGroup parent) {
50 | ViewHolder vh = null;
51 | if (convertView == null) {
52 | LayoutInflater layoutInflater = (LayoutInflater) mCtx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
53 | convertView = layoutInflater.inflate(R.layout.view_video, null);
54 |
55 | vh = new ViewHolder();
56 | vh.txtVwName = (TextView) convertView.findViewById(R.id.video_name_view);
57 | vh.txtVwGenre = (TextView) convertView.findViewById(R.id.video_genre);
58 | vh.txtVwDate = (TextView) convertView.findViewById(R.id.video_date);
59 |
60 | convertView.setTag(vh);
61 | } else {
62 | vh = (ViewHolder) convertView.getTag();
63 | }
64 |
65 | JSONObject jsonItem = (JSONObject) getItem(position);
66 | if (jsonItem != null) {
67 | try {
68 | vh.txtVwName.setText((String) jsonItem.get("videoNameCn"));
69 | vh.txtVwGenre.setText((String) jsonItem.get("genre"));
70 | vh.txtVwDate.setText((String) jsonItem.get("releaseDate"));
71 | } catch (JSONException e) {
72 | e.printStackTrace();
73 | }
74 | }
75 | return convertView;
76 | }
77 |
78 | class ViewHolder {
79 | TextView txtVwName;
80 | TextView txtVwGenre;
81 | TextView txtVwDate;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/player/VideoPlayer.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.player;
2 |
3 | /**
4 | * Interface for VideoPlayer component, defining universal methods like play, pause and stop
5 | * @author yuan (Email: yuan.tops@gmail.com) *
6 | * @date Mar 9, 2015
7 | */
8 | public interface VideoPlayer {
9 | void play();
10 | void pause();
11 | void stop();
12 | boolean isPlaying();
13 | int getDuration();
14 | void seekTo(int progress);
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/player/VideoPlayer_native.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.player;
2 |
3 | import java.util.Timer;
4 | import java.util.TimerTask;
5 |
6 | import com.yuantops.tvplayer.util.StringUtils;
7 |
8 | import android.content.Context;
9 | import android.media.AudioManager;
10 | import android.media.MediaPlayer;
11 | import android.media.MediaPlayer.OnBufferingUpdateListener;
12 | import android.media.MediaPlayer.OnPreparedListener;
13 | import android.os.Handler;
14 | import android.os.Message;
15 | import android.util.Log;
16 | import android.view.SurfaceHolder;
17 | import android.view.SurfaceView;
18 | import android.widget.SeekBar;
19 | import android.widget.TextView;
20 |
21 | /**
22 | * Videoplayer based on native MediaPlayer provided by official Android library;
23 | * Used for playing on-demand video stream in HTTP protocol;
24 | * Do not support real-time live video stream in RTSP protocol
25 | * 基于Andorid官方提供的原生MediaPlayer插件;
26 | * 用以播放HTTP格式的点播流;
27 | * 不支持RTSP格式的实时视频直播流
28 | * @author yuan (Email: yuan.tops@gmail.com)
29 | * @date Mar 9, 2015
30 | */
31 | public class VideoPlayer_native implements VideoPlayer{
32 | private static final String TAG = VideoPlayer_native.class.getSimpleName();
33 | private static final int CURR_TIME_VALUE = 8;
34 |
35 | private Context mContext;
36 | private SurfaceHolder surHolder;
37 | private SeekBar seekBar;
38 | private MediaPlayer mePlayer;
39 | private TextView vpCurrentTime, vpTotalTime;//currentTime, total video time length
40 | private int vpWidth, vpHeight;
41 |
42 | private String vUrl;
43 | private int vpBeginTime;//seekbar position when initializing
44 | private boolean flag = true;
45 | private Timer timer = new Timer();
46 |
47 | private TimerTask mTimerTask = new TimerTask() {
48 | @Override
49 | public void run() {
50 | if (mePlayer == null) {
51 | return;
52 | } else
53 | try {
54 | if (mePlayer.isPlaying()) {
55 | int position = (int) mePlayer.getCurrentPosition();
56 | int max = seekBar.getMax();
57 | if (position != 0) {
58 | Message msg = mHandler.obtainMessage(
59 | CURR_TIME_VALUE, position, max);
60 | mHandler.sendMessage(msg);
61 | try {
62 | Thread.sleep(500);
63 | } catch (InterruptedException e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | }
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | };
73 |
74 | Handler mHandler = new Handler() {
75 | public void handleMessage(android.os.Message msg) {
76 | switch (msg.what) {
77 | case CURR_TIME_VALUE:
78 | int position = msg.arg1;
79 | int max = msg.arg2;
80 | int duration = (int) mePlayer.getDuration();
81 | vpCurrentTime.setText(StringUtils.millisToString(position));
82 | vpTotalTime.setText(StringUtils.millisToString(duration));
83 | if (duration > 0) {
84 | int pos = max * position / duration;
85 | seekBar.setProgress(pos);
86 | }
87 | if (vpBeginTime != 0 && flag) {
88 | mePlayer.seekTo(vpBeginTime);
89 | seekBar.setProgress(max * vpBeginTime / duration);
90 | flag = false;
91 | }
92 | break;
93 | case 1:
94 | break;
95 | }
96 | };
97 | };
98 |
99 | private SurfaceHolder.Callback surCallbackListener = new SurfaceHolder.Callback() {
100 | @Override
101 | public void surfaceDestroyed(SurfaceHolder arg0) {
102 | }
103 | @Override
104 | public void surfaceCreated(SurfaceHolder arg0) {
105 | mePlayer = new MediaPlayer();
106 | mePlayer.setDisplay(surHolder);
107 | mePlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
108 | mePlayer.setOnBufferingUpdateListener(onBufferingUpdateListener);
109 | mePlayer.setOnPreparedListener(onPreparedListener);
110 |
111 | try {
112 | mePlayer.reset();
113 | mePlayer.setDataSource(vUrl);
114 | mePlayer.prepareAsync();
115 | } catch (Exception e) {
116 | e.printStackTrace();
117 | }
118 | }
119 | @Override
120 | public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
121 | mePlayer.setDisplay(surHolder);
122 | }
123 | };
124 |
125 | private OnBufferingUpdateListener onBufferingUpdateListener = new OnBufferingUpdateListener() {
126 | @Override
127 | public void onBufferingUpdate(MediaPlayer mp, int percent) {
128 | seekBar.setSecondaryProgress(percent);
129 | }
130 | };
131 |
132 | private OnPreparedListener onPreparedListener = new OnPreparedListener() {
133 | @Override
134 | public void onPrepared(MediaPlayer mp) {
135 | vpHeight = mp.getVideoHeight();
136 | vpWidth = mp.getVideoWidth();
137 | if (vpHeight != 0 && vpWidth != 0) {
138 | mp.start();// 播放视频
139 | }
140 | Log.v("mediaPlayer", "onPrepared");
141 | }
142 | };
143 |
144 | /**
145 | * @param surView
146 | * @param seekBar
147 | * @param vUrl
148 | * @param vpCurrentTime
149 | * @param vpTotalTime
150 | * @param vpBeginTime
151 | * @param context
152 | */
153 | public VideoPlayer_native(SurfaceView surView, SeekBar seekBar, String vUrl,
154 | TextView vpCurrentTime, TextView vpTotalTime,
155 | int vpBeginTime, Context context) {
156 |
157 | Log.v(TAG, "initialize");
158 | this.mContext = context;
159 | this.seekBar = seekBar;
160 | this.vUrl = vUrl;
161 | this.vpCurrentTime = vpCurrentTime;
162 | this.vpTotalTime = vpTotalTime;
163 | this.vpBeginTime = vpBeginTime;
164 |
165 | surHolder = surView.getHolder();
166 | surHolder.addCallback(surCallbackListener);
167 | surHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
168 |
169 | timer.schedule(mTimerTask, 0, 1000);
170 | }
171 |
172 | @Override
173 | public void play() {
174 | mePlayer.start();
175 | }
176 |
177 | @Override
178 | public void pause() {
179 | mePlayer.pause();
180 | }
181 |
182 | @Override
183 | public void stop() {
184 | if (mePlayer != null) {
185 | mePlayer.stop();
186 | mePlayer.release();
187 | mTimerTask.cancel();
188 | mePlayer = null;
189 | }
190 | }
191 |
192 | @Override
193 | public boolean isPlaying() {
194 | boolean flag;
195 | if (mePlayer == null) {
196 | flag = false;
197 | } else {
198 | flag = mePlayer.isPlaying();
199 | }
200 | return flag;
201 | }
202 |
203 | public int getCurrentPosition() {
204 | if (mePlayer == null) {
205 | return 0;
206 | } else {
207 | return (int) mePlayer.getCurrentPosition();
208 | }
209 | }
210 |
211 | public int getDuration() {
212 | return mePlayer.getDuration();
213 | }
214 |
215 | public void seekTo(int progress) {
216 | mePlayer.seekTo(progress);
217 | //Log.v(TAG, "seekTo() " + progress);
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/player/VideoPlayer_vitamio.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.player;
2 |
3 | import io.vov.vitamio.MediaPlayer;
4 | import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
5 | import io.vov.vitamio.MediaPlayer.OnCompletionListener;
6 | import io.vov.vitamio.MediaPlayer.OnPreparedListener;
7 | import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener;
8 | import android.content.Context;
9 | import android.graphics.PixelFormat;
10 | import android.util.Log;
11 | import android.view.SurfaceHolder;
12 | import android.view.SurfaceView;
13 |
14 | /**
15 | * Videoplayer based on thrid-party library Vitamio;
16 | * Used for playing real-time live video stream in RTSP protocol;
17 | * Also support on-demand video stream in HTTP protocol
18 | * 基于第三方的MediaPlayer插件 Vitamio;
19 | * 用以播放RTSP格式的实时视频直播流;
20 | * 同時支持HTTP格式的点播流
21 | * @author yuan (Email: yuan.tops@gmail.com)
22 | * @date Mar 9, 2015
23 | */
24 | public class VideoPlayer_vitamio implements VideoPlayer,
25 | OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener,
26 | OnVideoSizeChangedListener, SurfaceHolder.Callback {
27 | private static final String TAG = VideoPlayer.class.getSimpleName();
28 | private int mVideoWidth;
29 | private int mVideoHeight;
30 | private Context mContext; // VideoPlayerVitamio所处的上下文
31 | private SurfaceHolder surfaceHolder; //
32 | private MediaPlayer mediaPlayer; // 组件:MediaPlayer
33 | private String videoUrl; // 视频流URL
34 | private boolean mIsVideoSizeKnown = false;
35 | private boolean mIsVideoReadyToBePlayed = false;
36 |
37 | public VideoPlayer_vitamio(SurfaceView surfaceView, String videoUrl,
38 | Context context) {
39 | Log.v(TAG, "initialize");
40 | this.surfaceHolder = surfaceView.getHolder();
41 | this.videoUrl = videoUrl;
42 | this.mContext = context;
43 |
44 | this.surfaceHolder.addCallback(this);
45 | this.surfaceHolder.setFormat(PixelFormat.RGBX_8888);
46 | }
47 |
48 | @Override
49 | public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
50 | Log.v(TAG, "surfaceChanged");
51 | }
52 |
53 | @Override
54 | public void surfaceCreated(SurfaceHolder arg0) {
55 |
56 | doCleanUp();
57 |
58 | mediaPlayer = new MediaPlayer(mContext);
59 | try {
60 | Log.v(TAG + " >>videoUrl", videoUrl);
61 | mediaPlayer.setDataSource(videoUrl);
62 | mediaPlayer.setDisplay(surfaceHolder);
63 | mediaPlayer.prepareAsync();
64 | mediaPlayer.setOnBufferingUpdateListener(this);
65 | mediaPlayer.setOnCompletionListener(this);
66 | mediaPlayer.setOnPreparedListener(this);
67 | mediaPlayer.setOnVideoSizeChangedListener(this);
68 | // this.mContext.getSystemService(arg0)setVolumeControlStream(AudioManager.STREAM_MUSIC);
69 | } catch (Exception e) {
70 | //Log.e(TAG, "error: " + e.getMessage(), e);
71 | e.printStackTrace();
72 | }
73 | }
74 |
75 | @Override
76 | public void surfaceDestroyed(SurfaceHolder arg0) {
77 | Log.v(TAG, "surfaceDestroyed called");
78 |
79 | }
80 |
81 | @Override
82 | public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
83 | Log.v(TAG, "onVideoSizeChanged called");
84 | if (width == 0 || height == 0) {
85 | Log.e(TAG, "invalid video width(" + width + ") or height(" + height
86 | + ")");
87 | return;
88 | }
89 | mIsVideoSizeKnown = true;
90 | mVideoWidth = width;
91 | mVideoHeight = height;
92 | if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
93 | startVideoPlayback();
94 | }
95 | }
96 |
97 | @Override
98 | public void onPrepared(MediaPlayer mp) {
99 | Log.d(TAG, "onPrepared called");
100 | mIsVideoReadyToBePlayed = true;
101 | if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
102 | startVideoPlayback();
103 | }
104 | }
105 |
106 | @Override
107 | public void onCompletion(MediaPlayer mp) {
108 | Log.d(TAG, "onCompletion called");
109 | }
110 |
111 | @Override
112 | public void onBufferingUpdate(MediaPlayer mp, int percent) {
113 | Log.d(TAG, "onBufferingUpdate called");
114 | }
115 |
116 | private void doCleanUp() {
117 | mVideoWidth = 0;
118 | mVideoHeight = 0;
119 | mIsVideoReadyToBePlayed = false;
120 | mIsVideoSizeKnown = false;
121 | }
122 |
123 | private void startVideoPlayback() {
124 | Log.v(TAG, "startVideoPlayback");
125 | surfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
126 | mediaPlayer.start();
127 | }
128 |
129 | public void play() {
130 | mediaPlayer.start();
131 | }
132 |
133 | public void pause() {
134 | mediaPlayer.pause();
135 | }
136 |
137 | public void stop() {
138 | if (mediaPlayer != null) {
139 | // mediaPlayer.stop();
140 | mediaPlayer.release();
141 | mediaPlayer = null;
142 | }
143 | }
144 |
145 | public boolean isPlaying() {
146 | if (mediaPlayer == null) {
147 | return false;
148 | } else {
149 | return mediaPlayer.isPlaying();
150 | }
151 | }
152 |
153 | public int getCurrentPosition() {
154 | Log.v(TAG, "set returned postion 50");
155 | return 50;
156 | }
157 |
158 | public int getDuration() {
159 | return 0;
160 | }
161 |
162 | public void seekTo(int progress) {
163 | return;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/ui/LiveListFragment.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.AdapterView;
10 | import android.widget.ListView;
11 | import com.actionbarsherlock.app.SherlockFragment;
12 | import com.android.volley.Request;
13 | import com.android.volley.Response;
14 | import com.android.volley.VolleyError;
15 | import com.android.volley.toolbox.JsonArrayRequest;
16 | import com.yuantops.tvplayer.R;
17 | import com.yuantops.tvplayer.adapter.ListviewAdapter;
18 | import com.yuantops.tvplayer.util.VolleySingleton;
19 | import org.json.JSONArray;
20 | import org.json.JSONException;
21 | import org.json.JSONObject;
22 |
23 | /**
24 | * Created by yuan on 9/4/15.
25 | */
26 | public class LiveListFragment extends SherlockFragment {
27 | private static final String TAG = LiveListFragment.class.getSimpleName();
28 | private static JSONArray liveList = new JSONArray();
29 | private static final String LIVE_API_SUFFIX = "/topstv/debug";
30 | //private static final String LIVE_API_SUFFIX = "/videos";
31 | private static String LiveApiUrl;
32 | private static ListviewAdapter movielistAdapter;
33 |
34 | private ListView listViewLive;
35 | private AdapterView.OnItemClickListener clickListener;
36 |
37 | @Override
38 | public void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 |
41 | if (LiveApiUrl == null) {
42 | LiveApiUrl = MainActivity.url + LIVE_API_SUFFIX;
43 | }
44 | Log.v(TAG + " >>intent from MainActivity", MainActivity.url);
45 | }
46 |
47 | @Override
48 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
49 | Bundle savedInstanceState) {
50 | super.onCreateView(inflater, container, savedInstanceState);
51 | View v = inflater.inflate(R.layout.fragment_vod, container, false);
52 | listViewLive = (ListView) v.findViewById(R.id.listview_vod);
53 |
54 | if (liveList == null || liveList.length() == 0 && LiveApiUrl != null) {
55 | JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, LiveApiUrl, new Response.Listener() {
56 | @Override
57 | public void onResponse(JSONArray jsonArray) {
58 | for (int i = 0; i < jsonArray.length(); i++) {
59 | try {
60 | liveList.put((JSONObject)jsonArray.get(i));
61 | } catch (JSONException e) {
62 | e.printStackTrace();
63 | }
64 | }
65 | movielistAdapter.notifyDataSetChanged();
66 | }
67 | }, new Response.ErrorListener() {
68 | @Override
69 | public void onErrorResponse(VolleyError volleyError) {
70 | Log.e(TAG + " >>>response error", " ");
71 | volleyError.printStackTrace();
72 | }
73 | });
74 | VolleySingleton.getInstance(getActivity().getApplicationContext()).addToRequestQueue(request);
75 | }
76 |
77 | movielistAdapter = new ListviewAdapter(getActivity(), liveList);
78 | listViewLive.setAdapter(movielistAdapter);
79 |
80 | clickListener = new AdapterView.OnItemClickListener() {
81 | @Override
82 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
83 | String videoUrl;
84 | try {
85 | videoUrl = ((JSONObject) liveList.get(position)).getString("broadcastUrl");
86 | } catch (JSONException e) {
87 | videoUrl = null;
88 | e.printStackTrace();
89 | }
90 | Intent intent = new Intent(getActivity(), VideoPlayActivity.class);
91 | Bundle intentArgs = new Bundle();
92 | intentArgs.putString("broadcastUrl", videoUrl);
93 | intentArgs.putString("type", "LIVE");
94 | intent.putExtras(intentArgs);
95 | getActivity().startActivity(intent);
96 | }
97 | };
98 | listViewLive.setOnItemClickListener(clickListener);
99 |
100 | return v;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.ui;
2 |
3 | import java.util.HashMap;
4 |
5 | import com.actionbarsherlock.app.SherlockFragmentActivity;
6 | import com.yuantops.tvplayer.R;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.os.Bundle;
10 | import android.support.v4.app.Fragment;
11 | import android.support.v4.app.FragmentActivity;
12 | import android.support.v4.app.FragmentTransaction;
13 | import android.util.Log;
14 | import android.view.View;
15 | import android.widget.TabHost;
16 |
17 | public class MainActivity extends SherlockFragmentActivity {
18 | private static final String TAG = MainActivity.class.getSimpleName();
19 | public static String url = null;
20 |
21 | private TabHost mTabHost;
22 | private TabManager mTabManager;
23 |
24 | private String[] tabNames = { "点播", "直播" };
25 | private String[] tabTags = { "movie", "broadcast" };
26 | @SuppressWarnings("rawtypes")
27 | private Class[] fragmentClasses = { VODListFragment.class,
28 | LiveListFragment.class };
29 |
30 | public void onCreate(Bundle savedInstanceState) {
31 | Log.v(TAG, "onCreate()");
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.activity_main);
34 | setTheme(R.style.Theme_Sherlock_Light);
35 |
36 | Intent intent = getIntent();
37 | Bundle args = intent.getExtras();
38 |
39 | if (url == null) {
40 | url = args.getString("url");
41 | }
42 |
43 | mTabHost = (TabHost) findViewById(android.R.id.tabhost);
44 | mTabHost.setup();
45 | mTabManager = new TabManager(this, mTabHost, R.id.realtabcontent_1);
46 | for (int i = 0; i < tabNames.length; i++) {
47 | mTabManager.addTab(
48 | mTabHost.newTabSpec(tabTags[i]).setIndicator(tabNames[i]),
49 | fragmentClasses[i], args);
50 | }
51 | if (savedInstanceState != null) {
52 | mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
53 | }
54 | }
55 |
56 | @Override
57 | protected void onSaveInstanceState(Bundle outState) {
58 | super.onSaveInstanceState(outState);
59 | outState.putString("tab", mTabHost.getCurrentTabTag());
60 | }
61 |
62 | /**
63 | * This is a helper class that implements a generic mechanism for
64 | * associating fragments with the tabs in a tab host. It relies on a trick.
65 | * Normally a tab host has a simple API for supplying a View or Intent that
66 | * each tab will show. This is not sufficient for switching between
67 | * fragments. So instead we make the content part of the tab host 0dp high
68 | * (it is not shown) and the TabManager supplies its own dummy view to show
69 | * as the tab content. It listens to changes in tabs, and takes care of
70 | * switch to the correct fragment shown in a separate content area whenever
71 | * the selected tab changes.
72 | */
73 | public static class TabManager implements TabHost.OnTabChangeListener {
74 | private final FragmentActivity mActivity;
75 | private final TabHost mTabHost;
76 | private final int mContainerId;
77 | private final HashMap mTabs = new HashMap();
78 | TabInfo mLastTab;
79 |
80 | static final class TabInfo {
81 | private final String tag;
82 | private final Class> clss;
83 | private final Bundle args;
84 | private Fragment fragment;
85 |
86 | TabInfo(String _tag, Class> _class, Bundle _args) {
87 | tag = _tag;
88 | clss = _class;
89 | args = _args;
90 | }
91 | }
92 |
93 | public static class DummyTabFactory implements
94 | TabHost.TabContentFactory {
95 | private final Context mContext;
96 |
97 | public DummyTabFactory(Context context) {
98 | mContext = context;
99 | }
100 |
101 | @Override
102 | public View createTabContent(String tag) {
103 | View v = new View(mContext);
104 | v.setMinimumWidth(0);
105 | v.setMinimumHeight(0);
106 | return v;
107 | }
108 | }
109 |
110 | public TabManager(FragmentActivity activity, TabHost tabHost,
111 | int containerId) {
112 | mActivity = activity;
113 | mTabHost = tabHost;
114 | mContainerId = containerId;
115 | mTabHost.setOnTabChangedListener(this);
116 | }
117 |
118 | public void addTab(TabHost.TabSpec tabSpec, Class> clss, Bundle args) {
119 | tabSpec.setContent(new DummyTabFactory(mActivity));
120 | String tag = tabSpec.getTag();
121 |
122 | TabInfo info = new TabInfo(tag, clss, args);
123 |
124 | // Check to see if we already have a fragment for this tab, probably
125 | // from a previously saved state. If so, deactivate it, because our
126 | // initial state is that a tab isn't shown.
127 | info.fragment = mActivity.getSupportFragmentManager()
128 | .findFragmentByTag(tag);
129 | if (info.fragment != null && !info.fragment.isDetached()) {
130 | FragmentTransaction ft = mActivity.getSupportFragmentManager()
131 | .beginTransaction();
132 | ft.detach(info.fragment);
133 | ft.commit();
134 | }
135 |
136 | mTabs.put(tag, info);
137 | mTabHost.addTab(tabSpec);
138 | }
139 |
140 | @Override
141 | public void onTabChanged(String tabId) {
142 | TabInfo newTab = mTabs.get(tabId);
143 | if (mLastTab != newTab) {
144 | FragmentTransaction ft = mActivity.getSupportFragmentManager()
145 | .beginTransaction();
146 | if (mLastTab != null) {
147 | if (mLastTab.fragment != null) {
148 | ft.detach(mLastTab.fragment);
149 | }
150 | }
151 | if (newTab != null) {
152 | if (newTab.fragment == null) {
153 | newTab.fragment = Fragment.instantiate(mActivity,
154 | newTab.clss.getName(), newTab.args);
155 | ft.add(mContainerId, newTab.fragment, newTab.tag);
156 | } else {
157 | ft.attach(newTab.fragment);
158 | }
159 | }
160 |
161 | mLastTab = newTab;
162 | ft.commit();
163 | mActivity.getSupportFragmentManager()
164 | .executePendingTransactions();
165 | }
166 | }
167 | }
168 |
169 | long waitTime = 2000;
170 | long touchTime = 0;
171 | }
172 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/ui/VODListFragment.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.AdapterView;
10 | import android.widget.ListView;
11 | import com.actionbarsherlock.app.SherlockFragment;
12 | import com.android.volley.Request;
13 | import com.android.volley.Response;
14 | import com.android.volley.VolleyError;
15 | import com.android.volley.toolbox.JsonArrayRequest;
16 | import com.yuantops.tvplayer.R;
17 | import com.yuantops.tvplayer.adapter.ListviewAdapter;
18 | import com.yuantops.tvplayer.util.VolleySingleton;
19 | import org.json.JSONArray;
20 | import org.json.JSONException;
21 | import org.json.JSONObject;
22 |
23 | /**
24 | * Created by yuan on 9/4/15.
25 | */
26 | public class VODListFragment extends SherlockFragment {
27 | private static final String TAG = VODListFragment.class.getSimpleName();
28 | private static JSONArray movieList = new JSONArray();
29 | private static final String VOD_API_SUFFIX = "/topstv/debug";
30 | //private static final String VOD_API_SUFFIX = "/videos";
31 | private static String VODApiUrl;
32 | private static ListviewAdapter movielistAdapter;
33 |
34 | private ListView listViewVOD;
35 | private AdapterView.OnItemClickListener clickListener;
36 |
37 | @Override
38 | public void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 |
41 | if (VODApiUrl == null) {
42 | VODApiUrl = MainActivity.url + VOD_API_SUFFIX;
43 | }
44 | Log.v(TAG + " >>intent from MainActivity", MainActivity.url);
45 | }
46 |
47 | @Override
48 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
49 | Bundle savedInstanceState) {
50 | super.onCreateView(inflater, container, savedInstanceState);
51 | View v = inflater.inflate(R.layout.fragment_vod, container, false);
52 | listViewVOD = (ListView) v.findViewById(R.id.listview_vod);
53 |
54 | if (movieList == null || movieList.length() == 0 && VODApiUrl != null) {
55 | JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, VODApiUrl, new Response.Listener() {
56 | @Override
57 | public void onResponse(JSONArray jsonArray) {
58 | for (int i = 0; i < jsonArray.length(); i++) {
59 | try {
60 | movieList.put((JSONObject)jsonArray.get(i));
61 | } catch (JSONException e) {
62 | e.printStackTrace();
63 | }
64 | }
65 | movielistAdapter.notifyDataSetChanged();
66 | }
67 | }, new Response.ErrorListener() {
68 | @Override
69 | public void onErrorResponse(VolleyError volleyError) {
70 | Log.e(TAG + " >>>response error", " ");
71 | volleyError.printStackTrace();
72 | }
73 | });
74 | VolleySingleton.getInstance(getActivity().getApplicationContext()).addToRequestQueue(request);
75 | }
76 |
77 | movielistAdapter = new ListviewAdapter(getActivity(), movieList);
78 | listViewVOD.setAdapter(movielistAdapter);
79 |
80 | clickListener = new AdapterView.OnItemClickListener() {
81 | @Override
82 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
83 | String videoUrl;
84 | try {
85 | videoUrl = ((JSONObject) movieList.get(position)).getString("standardDefiUrl");
86 | } catch (JSONException e) {
87 | videoUrl = null;
88 | e.printStackTrace();
89 | }
90 | Intent intent = new Intent(getActivity(), VideoPlayActivity.class);
91 | Bundle intentArgs = new Bundle();
92 | intentArgs.putString("standardDefiUrl", videoUrl);
93 | intentArgs.putString("type", "VOD");
94 | intent.putExtras(intentArgs);
95 | getActivity().startActivity(intent);
96 | }
97 | };
98 | listViewVOD.setOnItemClickListener(clickListener);
99 |
100 | return v;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/ui/VideoPlayActivity.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.ui;
2 |
3 | import io.vov.vitamio.LibsChecker;
4 |
5 | import com.yuantops.tvplayer.R;
6 | import com.yuantops.tvplayer.player.VideoPlayer;
7 | import com.yuantops.tvplayer.player.VideoPlayer_native;
8 | import com.yuantops.tvplayer.player.VideoPlayer_vitamio;
9 |
10 | import android.app.Activity;
11 | import android.content.ComponentName;
12 | import android.content.Intent;
13 | import android.content.ServiceConnection;
14 | import android.content.pm.ActivityInfo;
15 | import android.graphics.Color;
16 | import android.os.Bundle;
17 | import android.os.IBinder;
18 | import android.util.DisplayMetrics;
19 | import android.util.Log;
20 | import android.view.SurfaceView;
21 | import android.view.View;
22 | import android.view.View.OnClickListener;
23 | import android.view.View.OnFocusChangeListener;
24 | import android.view.Window;
25 | import android.view.WindowManager;
26 | import android.widget.ImageButton;
27 | import android.widget.ImageView;
28 | import android.widget.SeekBar;
29 | import android.widget.SeekBar.OnSeekBarChangeListener;
30 | import android.widget.TextView;
31 |
32 | /**
33 | * Activity for playing on-demand/live video streams
34 | * 播放点播/直播流的Activity
35 | * @author yuan (Email: yuan.tops@gmail.com) *
36 | * @date Mar 12, 2015
37 | */
38 | public class VideoPlayActivity extends Activity{
39 | private static final String TAG = VideoPlayActivity.class.getSimpleName();
40 | private static final byte STANDARD = 1, HIGH = 2, SUPER = 3; //Device resolution for deciding video type
41 |
42 | private int viHeight, viWidth; //Video Player size: height, width
43 | private int initTime, curTime, totTime; //Video started at, current at, will end at
44 |
45 | private SurfaceView surView; //View for displaying video content; 显示视频内容的组件
46 | private SeekBar seekBar; //SeekBar
47 | private TextView curTimeView, totTimeView; //current moment, total time TextView under SeekBar
48 | private ImageButton playImgBtn; //play/pause button
49 | private VideoPlayer viPlayer; //
50 |
51 | private ServiceConnection conn = new ServiceConnection() {
52 | @Override
53 | public void onServiceConnected(ComponentName arg0, IBinder arg1) {
54 | Log.v(TAG, "Service connected");
55 | }
56 | @Override
57 | public void onServiceDisconnected(ComponentName arg0) {
58 | Log.v(TAG, "Service disconnected");
59 | }
60 | };
61 |
62 | @Override
63 | public void onCreate(Bundle savedInstanceState) {
64 | super.onCreate(savedInstanceState);
65 | Log.v(TAG, "onCreate()...");
66 |
67 | requestWindowFeature(Window.FEATURE_NO_TITLE); // 不显示标题
68 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, // 全屏
69 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
70 | this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 设置横屏播放
71 | this.setContentView(R.layout.activity_videoplay);
72 |
73 | initViewComponents();
74 | addViewListeners();
75 |
76 | //Retrieve video from intent
77 | Intent rcvIntent = getIntent();
78 | Bundle intentArgs = rcvIntent.getExtras();
79 | String type = intentArgs.getString("type");
80 | Log.d(TAG + ">>>type", type);
81 |
82 | String viUrl;
83 | if (type.equals("LIVE")) {
84 | viUrl = intentArgs.getString("broadcastUrl");
85 |
86 | if (!LibsChecker.checkVitamioLibs(this))
87 | return;
88 |
89 | viPlayer = new VideoPlayer_vitamio(surView, viUrl, this);
90 | } else {
91 | viUrl = intentArgs.getString("standardDefiUrl");
92 | viPlayer = new VideoPlayer_native(surView, seekBar, viUrl, curTimeView, totTimeView, 0, this);
93 | }
94 | }
95 |
96 | /**
97 | * Get references of view components
98 | */
99 | private void initViewComponents() {
100 | surView = (SurfaceView) this.findViewById(R.id.main_surface_view);
101 | seekBar = (SeekBar) this.findViewById(R.id.sb_video_player);
102 | curTimeView = (TextView) this.findViewById(R.id.tv_video_player_time);
103 | totTimeView = (TextView) this.findViewById(R.id.tv_video_player_length);
104 | playImgBtn = (ImageButton) this.findViewById(R.id.ib_play_pause);
105 |
106 | //Set focus, background image for play button
107 | playImgBtn.requestFocus();
108 | playImgBtn.setImageResource(R.drawable.pause);
109 |
110 | //Get screen size and thus deciding device resolution
111 | DisplayMetrics dm = new DisplayMetrics();
112 | dm = getResources().getDisplayMetrics();
113 | viHeight = dm.heightPixels;
114 | viWidth = dm.widthPixels;
115 | }
116 |
117 | /**
118 | * Add listeners to views
119 | */
120 | private void addViewListeners() {
121 | seekBar.setOnSeekBarChangeListener(seekBarListener);
122 | playImgBtn.setOnClickListener(clickListener);
123 | playImgBtn.setOnFocusChangeListener(viewFocusChangeListener);
124 | }
125 |
126 | /**
127 | * When moving seeking bar, update progress.
128 | */
129 | private OnSeekBarChangeListener seekBarListener = new OnSeekBarChangeListener() {
130 | int progress;
131 | @Override
132 | public void onProgressChanged(SeekBar seekBar, int progress0, boolean fromUser) {
133 | progress = (int) (progress0 * viPlayer.getDuration()
134 | / seekBar.getMax());
135 | }
136 | @Override
137 | public void onStartTrackingTouch(SeekBar arg0) {
138 | }
139 | @Override
140 | public void onStopTrackingTouch(SeekBar arg0) {
141 | viPlayer.seekTo(progress);
142 | //Log.v(TAG, "onStopTrackingTouch() called");
143 | }
144 | };
145 |
146 | /**
147 | * when clicking pause/play button, flip button's background image
148 | */
149 | private OnClickListener clickListener = new OnClickListener() {
150 | @Override
151 | public void onClick(View v) {
152 | switch (v.getId()) {
153 | case R.id.ib_play_pause:
154 | if (!viPlayer.isPlaying()) {
155 | viPlayer.play();
156 | playImgBtn.setImageResource(R.drawable.pause);
157 | } else {
158 | viPlayer.pause();
159 | playImgBtn.setImageResource(R.drawable.play);
160 | }
161 | break;
162 | default:
163 | break;
164 | }
165 | }
166 | };
167 |
168 | /**
169 | * when focus of view changes;
170 | */
171 | private OnFocusChangeListener viewFocusChangeListener = new OnFocusChangeListener() {
172 | @Override
173 | public void onFocusChange(View v, boolean hasFocus) {
174 | if (hasFocus) {
175 | v.setBackgroundColor(Color.GRAY);
176 | Log.v(TAG + " >focus changed", "has focus");
177 | } else {
178 | v.setBackgroundColor(Color.TRANSPARENT);
179 | Log.v(TAG + " >focus changed", "lose focus");
180 | }
181 | }
182 | };
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/ui/WebAPIServerActivity.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.ui;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.view.View.OnClickListener;
9 | import android.widget.Button;
10 | import android.widget.EditText;
11 | import com.yuantops.tvplayer.R;
12 | import com.yuantops.tvplayer.util.StringUtils;
13 | import com.yuantops.tvplayer.util.UIRobot;
14 |
15 | /**
16 | * Created by yuan on 9/3/15.
17 | */
18 | public class WebAPIServerActivity extends Activity implements OnClickListener {
19 | private static final String TAG = WebAPIServerActivity.class.getName();
20 |
21 | private EditText webServerIPEdtx;
22 | private Button enterBtn;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_web_server);
28 | webServerIPEdtx = (EditText) findViewById(R.id.web_api_server_ip);
29 | enterBtn = (Button) findViewById(R.id.web_server_enter);
30 | enterBtn.setOnClickListener(this);
31 | }
32 |
33 | public void onClick(View v) {
34 | String edtxContent = webServerIPEdtx.getText().toString();
35 | if (StringUtils.isEmpty(edtxContent)) {
36 | return;
37 | }
38 | Log.d(TAG, "Valid url, jump to MainPage");
39 | UIRobot.gotoMainPage(this, edtxContent);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/util/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.util;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.ByteArrayInputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.InputStreamReader;
8 | import java.text.DecimalFormat;
9 | import java.text.NumberFormat;
10 | import java.text.ParseException;
11 | import java.text.SimpleDateFormat;
12 | import java.util.Calendar;
13 | import java.util.Date;
14 | import java.util.Locale;
15 | import java.util.regex.Pattern;
16 |
17 | /**
18 | * 字符串操作工具包
19 | *
20 | * @author liux (http://my.oschina.net/liux)
21 | * @version 1.0
22 | * @created 2012-3-21
23 | */
24 | public class StringUtils {
25 | private final static Pattern emailer = Pattern
26 | .compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");
27 | // private final static SimpleDateFormat dateFormater = new
28 | // SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
29 | // private final static SimpleDateFormat dateFormater2 = new
30 | // SimpleDateFormat("yyyy-MM-dd");
31 |
32 | private static final Pattern IPAddresser = Pattern.compile(
33 | "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
34 | "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
35 | "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
36 | "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
37 |
38 | private final static ThreadLocal dateFormater = new ThreadLocal() {
39 | @Override
40 | protected SimpleDateFormat initialValue() {
41 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
42 | }
43 | };
44 |
45 | private final static ThreadLocal dateFormater2 = new ThreadLocal() {
46 | @Override
47 | protected SimpleDateFormat initialValue() {
48 | return new SimpleDateFormat("yyyy-MM-dd");
49 | }
50 | };
51 |
52 | /**
53 | * 将字符串转位日期类型
54 | *
55 | * @param sdate
56 | * @return
57 | */
58 | public static Date toDate(String sdate) {
59 | try {
60 | return dateFormater.get().parse(sdate);
61 | } catch (ParseException e) {
62 | return null;
63 | }
64 | }
65 |
66 | /**
67 | * 以友好的方式显示时间
68 | *
69 | * @param sdate
70 | * @return
71 | */
72 | public static String friendly_time(String sdate) {
73 | Date time = toDate(sdate);
74 | if (time == null) {
75 | return "Unknown";
76 | }
77 | String ftime = "";
78 | Calendar cal = Calendar.getInstance();
79 |
80 | // 判断是否是同一天
81 | String curDate = dateFormater2.get().format(cal.getTime());
82 | String paramDate = dateFormater2.get().format(time);
83 | if (curDate.equals(paramDate)) {
84 | int hour = (int) ((cal.getTimeInMillis() - time.getTime()) / 3600000);
85 | if (hour == 0)
86 | ftime = Math.max(
87 | (cal.getTimeInMillis() - time.getTime()) / 60000, 1)
88 | + "分钟前";
89 | else
90 | ftime = hour + "小时前";
91 | return ftime;
92 | }
93 |
94 | long lt = time.getTime() / 86400000;
95 | long ct = cal.getTimeInMillis() / 86400000;
96 | int days = (int) (ct - lt);
97 | if (days == 0) {
98 | int hour = (int) ((cal.getTimeInMillis() - time.getTime()) / 3600000);
99 | if (hour == 0)
100 | ftime = Math.max(
101 | (cal.getTimeInMillis() - time.getTime()) / 60000, 1)
102 | + "分钟前";
103 | else
104 | ftime = hour + "小时前";
105 | } else if (days == 1) {
106 | ftime = "昨天";
107 | } else if (days == 2) {
108 | ftime = "前天";
109 | } else if (days > 2 && days <= 10) {
110 | ftime = days + "天前";
111 | } else if (days > 10) {
112 | ftime = dateFormater2.get().format(time);
113 | }
114 | return ftime;
115 | }
116 |
117 | /**
118 | * 判断给定字符串时间是否为今日
119 | *
120 | * @param sdate
121 | * @return boolean
122 | */
123 | public static boolean isToday(String sdate) {
124 | boolean b = false;
125 | Date time = toDate(sdate);
126 | Date today = new Date();
127 | if (time != null) {
128 | String nowDate = dateFormater2.get().format(today);
129 | String timeDate = dateFormater2.get().format(time);
130 | if (nowDate.equals(timeDate)) {
131 | b = true;
132 | }
133 | }
134 | return b;
135 | }
136 |
137 | /**
138 | * 返回long类型的今天的日期
139 | * @return
140 | */
141 | public static long getToday() {
142 | Calendar cal = Calendar.getInstance();
143 | String curDate = dateFormater2.get().format(cal.getTime());
144 | curDate = curDate.replace("-", "");
145 | return Long.parseLong(curDate);
146 | }
147 |
148 | /**
149 | * 判断给定字符串是否空白串。 空白串是指由空格、制表符、回车符、换行符组成的字符串 若输入字符串为null或空字符串,返回true
150 | *
151 | * @param input
152 | * @return boolean
153 | */
154 | public static boolean isEmpty(String input) {
155 | if (input == null || "".equals(input))
156 | return true;
157 |
158 | for (int i = 0; i < input.length(); i++) {
159 | char c = input.charAt(i);
160 | if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
161 | return false;
162 | }
163 | }
164 | return true;
165 | }
166 |
167 | /**
168 | * 判断是不是一个合法的电子邮件地址
169 | *
170 | * @param email
171 | * @return
172 | */
173 | public static boolean isEmail(String email) {
174 | if (email == null || email.trim().length() == 0)
175 | return false;
176 | return emailer.matcher(email).matches();
177 | }
178 |
179 | /**
180 | * 判断是不是合法的IP地址
181 | * @param ip
182 | * @return
183 | */
184 | public static boolean isValidIPAddress(String ip) {
185 | if (ip == null || ip.equals("")) {
186 | return false;
187 | }
188 | return IPAddresser.matcher(ip).matches();
189 | }
190 |
191 | /**
192 | * 字符串转整数
193 | *
194 | * @param str
195 | * @param defValue
196 | * @return
197 | */
198 | public static int toInt(String str, int defValue) {
199 | try {
200 | return Integer.parseInt(str);
201 | } catch (Exception e) {
202 | }
203 | return defValue;
204 | }
205 |
206 | /**
207 | * 对象转整数
208 | *
209 | * @param obj
210 | * @return 转换异常返回 0
211 | */
212 | public static int toInt(Object obj) {
213 | if (obj == null)
214 | return 0;
215 | return toInt(obj.toString(), 0);
216 | }
217 |
218 | /**
219 | * 对象转整数
220 | *
221 | * @param obj
222 | * @return 转换异常返回 0
223 | */
224 | public static long toLong(String obj) {
225 | try {
226 | return Long.parseLong(obj);
227 | } catch (Exception e) {
228 | }
229 | return 0;
230 | }
231 |
232 | /**
233 | * 字符串转布尔值
234 | *
235 | * @param b
236 | * @return 转换异常返回 false
237 | */
238 | public static boolean toBool(String b) {
239 | try {
240 | return Boolean.parseBoolean(b);
241 | } catch (Exception e) {
242 | }
243 | return false;
244 | }
245 |
246 | /**
247 | * 将一个InputStream流转换成字符串
248 | * @param is
249 | * @return
250 | */
251 | public static String toConvertString(InputStream is) {
252 | StringBuffer res = new StringBuffer();
253 | InputStreamReader isr = new InputStreamReader(is);
254 | BufferedReader read = new BufferedReader(isr);
255 | try {
256 | String line;
257 | line = read.readLine();
258 | while (line != null) {
259 | res.append(line);
260 | line = read.readLine();
261 | }
262 | } catch (IOException e) {
263 | e.printStackTrace();
264 | } finally {
265 | try {
266 | if (null != isr) {
267 | isr.close();
268 | isr.close();
269 | }
270 | if (null != read) {
271 | read.close();
272 | read = null;
273 | }
274 | if (null != is) {
275 | is.close();
276 | is = null;
277 | }
278 | } catch (IOException e) {
279 | }
280 | }
281 | return res.toString();
282 | }
283 |
284 | /**
285 | * Convert time to a string
286 | *
287 | * @param millis
288 | * e.g.time/length from file
289 | * @return formated string (hh:)mm:ss
290 | */
291 | public static String millisToString(long millis) {
292 | boolean negative = millis < 0;
293 | millis = java.lang.Math.abs(millis);
294 |
295 | millis /= 1000;
296 | int sec = (int) (millis % 60);
297 | millis /= 60;
298 | int min = (int) (millis % 60);
299 | millis /= 60;
300 | int hours = (int) millis;
301 |
302 | String time;
303 | DecimalFormat format = (DecimalFormat) NumberFormat
304 | .getInstance(Locale.US);
305 | format.applyPattern("00");
306 | if (millis > 0) {
307 | time = (negative ? "-" : "") + hours + ":" + format.format(min)
308 | + ":" + format.format(sec);
309 | } else {
310 | time = (negative ? "-" : "") + min + ":" + format.format(sec);
311 | }
312 | return time;
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/util/UIRobot.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.util;
2 |
3 | import android.os.Bundle;
4 | import com.yuantops.tvplayer.ui.*;
5 |
6 | import android.app.Activity;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.util.Log;
10 | import android.widget.Toast;
11 |
12 | /**
13 | * 处理与UI相关的工具类,包括Activity跳转、显示Dialog、显示Toast
14 | * @author admin (Email: yuan.tops@gmail.com)
15 | * @date 2015-1-7
16 | */
17 | public class UIRobot {
18 | public static final String TAG = UIRobot.class.getSimpleName();
19 |
20 | public static void gotoMainPage(Context context, String url) {
21 | Intent intent = new Intent(context, MainActivity.class);
22 | Bundle bundle = new Bundle();
23 | bundle.putString("url", url);
24 | intent.putExtras(bundle);
25 | // intent.putExtra("url", url);
26 | context.startActivity(intent);
27 | ((Activity)context).finish();
28 | }
29 |
30 | /**
31 | * 显示提示信息
32 | * @param mContext
33 | * @param string
34 | */
35 | public static void showToast(Context mContext, String string) {
36 | if(!StringUtils.isEmpty(string)) {
37 | Toast.makeText(mContext, string, Toast.LENGTH_SHORT).show();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yuantops/tvplayer/util/VolleySingleton.java:
--------------------------------------------------------------------------------
1 | package com.yuantops.tvplayer.util;
2 |
3 | import android.content.Context;
4 | import com.android.volley.Request;
5 | import com.android.volley.RequestQueue;
6 | import com.android.volley.VolleyError;
7 | import com.android.volley.toolbox.Volley;
8 | import org.apache.http.protocol.RequestExpectContinue;
9 |
10 | /**
11 | * Created by yuan on 9/5/15.
12 | */
13 | public class VolleySingleton {
14 | private static final String TAG = VolleySingleton.class.getSimpleName();
15 |
16 | private static VolleySingleton mInstance;
17 | private RequestQueue mRequestQueue;
18 | private Context mCtx;
19 |
20 | private VolleySingleton(Context context) {
21 | mCtx = context;
22 | mRequestQueue = getRequestQueue();
23 | }
24 |
25 | public static synchronized VolleySingleton getInstance(Context context) {
26 | if (mInstance == null) {
27 | mInstance = new VolleySingleton(context);
28 | }
29 | return mInstance;
30 | }
31 |
32 | private RequestQueue getRequestQueue() {
33 | if (mRequestQueue == null) {
34 | mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
35 | }
36 | return mRequestQueue;
37 | }
38 |
39 | public void addToRequestQueue(Request req) {
40 | getRequestQueue().add(req);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_seekbar_thumb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-mdpi/ic_seekbar_thumb.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-mdpi/pause.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-mdpi/play.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ratingbar_full.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/star_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-mdpi/star_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/star_unselect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-mdpi/star_unselect.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/vlc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-mdpi/vlc.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
13 |
14 |
20 |
21 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
18 |
19 |
24 |
25 |
26 |
31 |
32 |
38 |
39 |
45 |
46 |
53 |
54 |
62 |
63 |
70 |
71 |
72 |
76 |
77 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_videoplay.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
18 |
19 |
24 |
25 |
26 |
31 |
32 |
38 |
39 |
45 |
46 |
53 |
54 |
62 |
63 |
70 |
71 |
72 |
76 |
77 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_web_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
13 |
14 |
18 |
19 |
23 |
24 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_live.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_vod.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_video.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
20 |
21 |
22 |
26 |
27 |
35 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ratingbar_style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TopsTVPlayer
5 | Settings
6 | Hello world!
7 | Web API Server\'s IP:
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:1.2.3'
8 | }
9 | }
10 |
11 | allprojects {
12 | repositories {
13 | jcenter()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuantops/TopsTVPlayer/ccbe8d28f43cf5aa0724a3bd7c5c8e53edb1e427/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------