Commit 46f3a709817f5e22fe9b10708ce2dbdffb881b11
1 parent
889f3c14
Vitamio...
Showing
83 changed files
with
2100 additions
and
4 deletions
VitamioBundle/.classpath
0 โ 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<classpath> | ||
3 | + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> | ||
4 | + <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> | ||
5 | + <classpathentry kind="src" path="src"/> | ||
6 | + <classpathentry kind="src" path="gen"/> | ||
7 | + <classpathentry kind="output" path="bin/classes"/> | ||
8 | +</classpath> |
VitamioBundle/.gitignore
0 โ 100644
1 | +# built application files | ||
2 | +*.apk | ||
3 | +*.ap_ | ||
4 | + | ||
5 | +# files for the dex VM | ||
6 | +*.dex | ||
7 | + | ||
8 | +# Java class files | ||
9 | +*.class | ||
10 | + | ||
11 | +# generated files | ||
12 | +bin/ | ||
13 | +gen/ | ||
14 | +obj/ | ||
15 | + | ||
16 | +# Local configuration file (sdk path, etc) | ||
17 | +local.properties | ||
18 | + | ||
19 | +# Eclipse project files | ||
20 | +.classpath | ||
21 | +.project |
VitamioBundle/.project
0 โ 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<projectDescription> | ||
3 | + <name>io.vov.vitamio.activity.InitActivity</name> | ||
4 | + <comment></comment> | ||
5 | + <projects> | ||
6 | + </projects> | ||
7 | + <buildSpec> | ||
8 | + <buildCommand> | ||
9 | + <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> | ||
10 | + <arguments> | ||
11 | + </arguments> | ||
12 | + </buildCommand> | ||
13 | + <buildCommand> | ||
14 | + <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> | ||
15 | + <arguments> | ||
16 | + </arguments> | ||
17 | + </buildCommand> | ||
18 | + <buildCommand> | ||
19 | + <name>org.eclipse.jdt.core.javabuilder</name> | ||
20 | + <arguments> | ||
21 | + </arguments> | ||
22 | + </buildCommand> | ||
23 | + <buildCommand> | ||
24 | + <name>com.android.ide.eclipse.adt.ApkBuilder</name> | ||
25 | + <arguments> | ||
26 | + </arguments> | ||
27 | + </buildCommand> | ||
28 | + </buildSpec> | ||
29 | + <natures> | ||
30 | + <nature>com.android.ide.eclipse.adt.AndroidNature</nature> | ||
31 | + <nature>org.eclipse.jdt.core.javanature</nature> | ||
32 | + </natures> | ||
33 | +</projectDescription> |
VitamioBundle/.settings/org.eclipse.jdt.core.prefs
0 โ 100644
1 | +eclipse.preferences.version=1 | ||
2 | +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled | ||
3 | +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 | ||
4 | +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve | ||
5 | +org.eclipse.jdt.core.compiler.compliance=1.6 | ||
6 | +org.eclipse.jdt.core.compiler.debug.lineNumber=generate | ||
7 | +org.eclipse.jdt.core.compiler.debug.localVariable=generate | ||
8 | +org.eclipse.jdt.core.compiler.debug.sourceFile=generate | ||
9 | +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error | ||
10 | +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error | ||
11 | +org.eclipse.jdt.core.compiler.source=1.6 |
VitamioBundle/AndroidManifest.xml
0 โ 100644
1 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
2 | + package="io.vov.vitamio" | ||
3 | + android:versionCode="300" | ||
4 | + android:versionName="3.0" > | ||
5 | + | ||
6 | + <uses-sdk | ||
7 | + android:minSdkVersion="7" | ||
8 | + android:targetSdkVersion="16" /> | ||
9 | + | ||
10 | + <application | ||
11 | + android:icon="@drawable/ic_launcher" | ||
12 | + android:label="@string/vitamio_name" > | ||
13 | + <activity | ||
14 | + android:name="io.vov.vitamio.activity.InitActivity" | ||
15 | + android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation" | ||
16 | + android:launchMode="singleTop" | ||
17 | + android:theme="@android:style/Theme.NoTitleBar" | ||
18 | + android:windowSoftInputMode="stateAlwaysHidden" /> | ||
19 | + </application> | ||
20 | + | ||
21 | +</manifest> | ||
0 | \ No newline at end of file | 22 | \ No newline at end of file |
VitamioBundle/README.md
0 โ 100644
VitamioBundle/VitamioBundle.tar.gz
0 โ 100644
No preview for this file type
VitamioBundle/bin/AndroidManifest.xml
0 โ 100644
1 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
2 | + package="io.vov.vitamio" | ||
3 | + android:versionCode="300" | ||
4 | + android:versionName="3.0" > | ||
5 | + | ||
6 | + <uses-sdk | ||
7 | + android:minSdkVersion="7" | ||
8 | + android:targetSdkVersion="16" /> | ||
9 | + | ||
10 | + <application | ||
11 | + android:icon="@drawable/ic_launcher" | ||
12 | + android:label="@string/vitamio_name" > | ||
13 | + <activity | ||
14 | + android:name="io.vov.vitamio.activity.InitActivity" | ||
15 | + android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation" | ||
16 | + android:launchMode="singleTop" | ||
17 | + android:theme="@android:style/Theme.NoTitleBar" | ||
18 | + android:windowSoftInputMode="stateAlwaysHidden" /> | ||
19 | + </application> | ||
20 | + | ||
21 | +</manifest> | ||
0 | \ No newline at end of file | 22 | \ No newline at end of file |
VitamioBundle/bin/classes/io/vov/vitamio/BuildConfig.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R$attr.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R$drawable.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R$id.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R$layout.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R$raw.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R$string.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R$style.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/R.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/activity/InitActivity$1.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/activity/InitActivity$UIHandler.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/activity/InitActivity.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/CenterLayout$LayoutParams.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/CenterLayout.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/MediaController$1.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/MediaController$2.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/MediaController$3.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/MediaController$MediaPlayerControl.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/MediaController$OnHiddenListener.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/MediaController$OnShownListener.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/MediaController.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/OutlineTextView.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$1.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$2.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$3.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$4$1.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$4.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$5.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$6.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$7.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$8.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView$9.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/classes/io/vov/vitamio/widget/VideoView.class
0 โ 100644
No preview for this file type
VitamioBundle/bin/io.vov.vitamio.activity.initactivity.jar
0 โ 100644
No preview for this file type
VitamioBundle/bin/jarlist.cache
0 โ 100644
VitamioBundle/bin/res/drawable-hdpi/ic_launcher.png
0 โ 100644
791 Bytes
VitamioBundle/bin/res/drawable-hdpi/mediacontroller_bg.png
0 โ 100644
129 Bytes
VitamioBundle/bin/res/drawable-hdpi/mediacontroller_pause01.png
0 โ 100644
599 Bytes
VitamioBundle/bin/res/drawable-hdpi/mediacontroller_pause02.png
0 โ 100644
710 Bytes
VitamioBundle/bin/res/drawable-hdpi/mediacontroller_play01.png
0 โ 100644
922 Bytes
VitamioBundle/bin/res/drawable-hdpi/mediacontroller_play02.png
0 โ 100644
1.04 KB
VitamioBundle/bin/res/drawable-hdpi/mediacontroller_seekbar01.png
0 โ 100644
456 Bytes
VitamioBundle/bin/res/drawable-hdpi/mediacontroller_seekbar02.png
0 โ 100644
103 Bytes
VitamioBundle/bin/res/drawable-xhdpi/ic_launcher.png
0 โ 100644
973 Bytes
VitamioBundle/build.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project name="VitamioBundle" default="help"> | ||
3 | + | ||
4 | + <!-- The local.properties file is created and updated by the 'android' tool. | ||
5 | + It contains the path to the SDK. It should *NOT* be checked into | ||
6 | + Version Control Systems. --> | ||
7 | + <property file="local.properties" /> | ||
8 | + | ||
9 | + <!-- The ant.properties file can be created by you. It is only edited by the | ||
10 | + 'android' tool to add properties to it. | ||
11 | + This is the place to change some Ant specific build properties. | ||
12 | + Here are some properties you may want to change/update: | ||
13 | + | ||
14 | + source.dir | ||
15 | + The name of the source directory. Default is 'src'. | ||
16 | + out.dir | ||
17 | + The name of the output directory. Default is 'bin'. | ||
18 | + | ||
19 | + For other overridable properties, look at the beginning of the rules | ||
20 | + files in the SDK, at tools/ant/build.xml | ||
21 | + | ||
22 | + Properties related to the SDK location or the project target should | ||
23 | + be updated using the 'android' tool with the 'update' action. | ||
24 | + | ||
25 | + This file is an integral part of the build system for your | ||
26 | + application and should be checked into Version Control Systems. | ||
27 | + | ||
28 | + --> | ||
29 | + <property file="ant.properties" /> | ||
30 | + | ||
31 | + <!-- if sdk.dir was not set from one of the property file, then | ||
32 | + get it from the ANDROID_HOME env var. | ||
33 | + This must be done before we load project.properties since | ||
34 | + the proguard config can use sdk.dir --> | ||
35 | + <property environment="env" /> | ||
36 | + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> | ||
37 | + <isset property="env.ANDROID_HOME" /> | ||
38 | + </condition> | ||
39 | + | ||
40 | + <!-- The project.properties file is created and updated by the 'android' | ||
41 | + tool, as well as ADT. | ||
42 | + | ||
43 | + This contains project specific properties such as project target, and library | ||
44 | + dependencies. Lower level build properties are stored in ant.properties | ||
45 | + (or in .classpath for Eclipse projects). | ||
46 | + | ||
47 | + This file is an integral part of the build system for your | ||
48 | + application and should be checked into Version Control Systems. --> | ||
49 | + <loadproperties srcFile="project.properties" /> | ||
50 | + | ||
51 | + <!-- quick check on sdk.dir --> | ||
52 | + <fail | ||
53 | + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." | ||
54 | + unless="sdk.dir" | ||
55 | + /> | ||
56 | + | ||
57 | + <!-- | ||
58 | + Import per project custom build rules if present at the root of the project. | ||
59 | + This is the place to put custom intermediary targets such as: | ||
60 | + -pre-build | ||
61 | + -pre-compile | ||
62 | + -post-compile (This is typically used for code obfuscation. | ||
63 | + Compiled code location: ${out.classes.absolute.dir} | ||
64 | + If this is not done in place, override ${out.dex.input.absolute.dir}) | ||
65 | + -post-package | ||
66 | + -post-build | ||
67 | + -pre-clean | ||
68 | + --> | ||
69 | + <import file="custom_rules.xml" optional="true" /> | ||
70 | + | ||
71 | + <!-- Import the actual build file. | ||
72 | + | ||
73 | + To customize existing targets, there are two options: | ||
74 | + - Customize only one target: | ||
75 | + - copy/paste the target into this file, *before* the | ||
76 | + <import> task. | ||
77 | + - customize it to your needs. | ||
78 | + - Customize the whole content of build.xml | ||
79 | + - copy/paste the content of the rules files (minus the top node) | ||
80 | + into this file, replacing the <import> task. | ||
81 | + - customize to your needs. | ||
82 | + | ||
83 | + *********************** | ||
84 | + ****** IMPORTANT ****** | ||
85 | + *********************** | ||
86 | + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, | ||
87 | + in order to avoid having your file be overridden by tools such as "android update project" | ||
88 | + --> | ||
89 | + <!-- version-tag: 1 --> | ||
90 | + <import file="${sdk.dir}/tools/ant/build.xml" /> | ||
91 | + | ||
92 | +</project> |
VitamioBundle/gen/io/vov/vitamio/BuildConfig.java
0 โ 100644
VitamioBundle/gen/io/vov/vitamio/R.java
0 โ 100644
1 | +/* AUTO-GENERATED FILE. DO NOT MODIFY. | ||
2 | + * | ||
3 | + * This class was automatically generated by the | ||
4 | + * aapt tool from the resource data it found. It | ||
5 | + * should not be modified by hand. | ||
6 | + */ | ||
7 | + | ||
8 | +package io.vov.vitamio; | ||
9 | + | ||
10 | +public final class R { | ||
11 | + public static final class attr { | ||
12 | + } | ||
13 | + public static final class drawable { | ||
14 | + public static int ic_launcher=0x7f020000; | ||
15 | + public static int mediacontroller_bg=0x7f020001; | ||
16 | + public static int mediacontroller_pause01=0x7f020002; | ||
17 | + public static int mediacontroller_pause02=0x7f020003; | ||
18 | + public static int mediacontroller_pause_button=0x7f020004; | ||
19 | + public static int mediacontroller_play01=0x7f020005; | ||
20 | + public static int mediacontroller_play02=0x7f020006; | ||
21 | + public static int mediacontroller_play_button=0x7f020007; | ||
22 | + public static int mediacontroller_seekbar=0x7f020008; | ||
23 | + public static int mediacontroller_seekbar01=0x7f020009; | ||
24 | + public static int mediacontroller_seekbar02=0x7f02000a; | ||
25 | + public static int mediacontroller_seekbar_thumb=0x7f02000b; | ||
26 | + } | ||
27 | + public static final class id { | ||
28 | + public static int mediacontroller_file_name=0x7f070004; | ||
29 | + public static int mediacontroller_play_pause=0x7f070000; | ||
30 | + public static int mediacontroller_seekbar=0x7f070003; | ||
31 | + public static int mediacontroller_time_current=0x7f070001; | ||
32 | + public static int mediacontroller_time_total=0x7f070002; | ||
33 | + } | ||
34 | + public static final class layout { | ||
35 | + public static int mediacontroller=0x7f030000; | ||
36 | + } | ||
37 | + public static final class raw { | ||
38 | + public static int libarm=0x7f040000; | ||
39 | + } | ||
40 | + public static final class string { | ||
41 | + public static int mediacontroller_play_pause=0x7f050006; | ||
42 | + public static int vitamio_init_decoders=0x7f050001; | ||
43 | + public static int vitamio_name=0x7f050000; | ||
44 | + public static int vitamio_videoview_error_button=0x7f050005; | ||
45 | + public static int vitamio_videoview_error_text_invalid_progressive_playback=0x7f050003; | ||
46 | + public static int vitamio_videoview_error_text_unknown=0x7f050004; | ||
47 | + public static int vitamio_videoview_error_title=0x7f050002; | ||
48 | + } | ||
49 | + public static final class style { | ||
50 | + public static int MediaController_SeekBar=0x7f060000; | ||
51 | + public static int MediaController_Text=0x7f060001; | ||
52 | + } | ||
53 | +} |
VitamioBundle/ic_launcher-web.png
0 โ 100644
14 KB
VitamioBundle/libs/vitamio.jar
0 โ 100644
No preview for this file type
VitamioBundle/proguard-project.txt
0 โ 100644
1 | +# To enable ProGuard in your project, edit project.properties | ||
2 | +# to define the proguard.config property as described in that file. | ||
3 | +# | ||
4 | +# Add project specific ProGuard rules here. | ||
5 | +# By default, the flags in this file are appended to flags specified | ||
6 | +# in ${sdk.dir}/tools/proguard/proguard-android.txt | ||
7 | +# You can edit the include path and order by changing the ProGuard | ||
8 | +# include property in project.properties. | ||
9 | +# | ||
10 | +# For more details, see | ||
11 | +# http://developer.android.com/guide/developing/tools/proguard.html | ||
12 | + | ||
13 | +# Add any project specific keep options here: | ||
14 | + | ||
15 | +# If your project uses WebView with JS, uncomment the following | ||
16 | +# and specify the fully qualified class name to the JavaScript interface | ||
17 | +# class: | ||
18 | +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
19 | +# public *; | ||
20 | +#} |
VitamioBundle/project.properties
0 โ 100644
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-15 | ||
15 | +android.library=true |
VitamioBundle/res/drawable-hdpi/ic_launcher.png
0 โ 100644
2.74 KB
VitamioBundle/res/drawable-hdpi/mediacontroller_bg.png
0 โ 100644
3.66 KB
VitamioBundle/res/drawable-hdpi/mediacontroller_pause01.png
0 โ 100644
4.6 KB
VitamioBundle/res/drawable-hdpi/mediacontroller_pause02.png
0 โ 100644
4.93 KB
VitamioBundle/res/drawable-hdpi/mediacontroller_play01.png
0 โ 100644
5.06 KB
VitamioBundle/res/drawable-hdpi/mediacontroller_play02.png
0 โ 100644
5.32 KB
VitamioBundle/res/drawable-hdpi/mediacontroller_seekbar01.png
0 โ 100644
894 Bytes
VitamioBundle/res/drawable-hdpi/mediacontroller_seekbar02.png
0 โ 100644
932 Bytes
VitamioBundle/res/drawable-xhdpi/ic_launcher.png
0 โ 100644
3.29 KB
VitamioBundle/res/drawable/mediacontroller_pause_button.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<selector xmlns:android="http://schemas.android.com/apk/res/android"> | ||
3 | + | ||
4 | + <item android:drawable="@drawable/mediacontroller_pause02" android:state_focused="true" android:state_pressed="false"/> | ||
5 | + <item android:drawable="@drawable/mediacontroller_pause02" android:state_focused="true" android:state_pressed="true"/> | ||
6 | + <item android:drawable="@drawable/mediacontroller_pause02" android:state_focused="false" android:state_pressed="true"/> | ||
7 | + <item android:drawable="@drawable/mediacontroller_pause01"/> | ||
8 | + | ||
9 | +</selector> | ||
0 | \ No newline at end of file | 10 | \ No newline at end of file |
VitamioBundle/res/drawable/mediacontroller_play_button.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<selector xmlns:android="http://schemas.android.com/apk/res/android"> | ||
3 | + | ||
4 | + <item android:drawable="@drawable/mediacontroller_play02" android:state_focused="true" android:state_pressed="false"/> | ||
5 | + <item android:drawable="@drawable/mediacontroller_play02" android:state_focused="true" android:state_pressed="true"/> | ||
6 | + <item android:drawable="@drawable/mediacontroller_play02" android:state_focused="false" android:state_pressed="true"/> | ||
7 | + <item android:drawable="@drawable/mediacontroller_play01"/> | ||
8 | + | ||
9 | +</selector> | ||
0 | \ No newline at end of file | 10 | \ No newline at end of file |
VitamioBundle/res/drawable/mediacontroller_seekbar.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > | ||
3 | + | ||
4 | + <item | ||
5 | + android:id="@android:id/background" | ||
6 | + android:drawable="@drawable/mediacontroller_seekbar02"/> | ||
7 | + <item android:id="@android:id/secondaryProgress"> | ||
8 | + <clip> | ||
9 | + <shape> | ||
10 | + <solid android:color="#00000000" /> | ||
11 | + </shape> | ||
12 | + </clip> | ||
13 | + </item> | ||
14 | + <item android:id="@android:id/progress"> | ||
15 | + <clip> | ||
16 | + <layer-list> | ||
17 | + <item | ||
18 | + android:bottom="2.0dip" | ||
19 | + android:left="2.0dip" | ||
20 | + android:right="2.0dip" | ||
21 | + android:top="2.0dip"> | ||
22 | + <bitmap | ||
23 | + android:gravity="center_vertical|fill_vertical|left" | ||
24 | + android:src="@drawable/mediacontroller_seekbar01" | ||
25 | + android:tileMode="disabled" /> | ||
26 | + </item> | ||
27 | + </layer-list> | ||
28 | + </clip> | ||
29 | + </item> | ||
30 | + | ||
31 | +</layer-list> | ||
0 | \ No newline at end of file | 32 | \ No newline at end of file |
VitamioBundle/res/drawable/mediacontroller_seekbar_thumb.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<shape xmlns:android="http://schemas.android.com/apk/res/android" | ||
3 | + android:shape="ring" > | ||
4 | + | ||
5 | + <solid android:color="#00000000" /> | ||
6 | + | ||
7 | + <size | ||
8 | + android:height="40dip" | ||
9 | + android:width="40dip" /> | ||
10 | + | ||
11 | +</shape> | ||
0 | \ No newline at end of file | 12 | \ No newline at end of file |
VitamioBundle/res/layout/mediacontroller.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
3 | + android:layout_width="match_parent" | ||
4 | + android:layout_height="74dip" | ||
5 | + android:layout_alignParentBottom="true" | ||
6 | + android:layout_marginBottom="0.0dip" | ||
7 | + android:layout_marginLeft="0.0dip" | ||
8 | + android:layout_marginRight="0.0dip" | ||
9 | + android:background="@drawable/mediacontroller_bg" | ||
10 | + android:orientation="horizontal" > | ||
11 | + | ||
12 | + <ImageButton | ||
13 | + android:id="@+id/mediacontroller_play_pause" | ||
14 | + android:layout_width="54.6dip" | ||
15 | + android:layout_height="32dip" | ||
16 | + android:layout_alignParentRight="true" | ||
17 | + android:layout_centerHorizontal="true" | ||
18 | + android:layout_centerVertical="true" | ||
19 | + android:layout_marginRight="7.0dip" | ||
20 | + android:background="#00000000" | ||
21 | + android:contentDescription="@string/mediacontroller_play_pause" | ||
22 | + android:gravity="center" | ||
23 | + android:src="@drawable/mediacontroller_pause_button" /> | ||
24 | + | ||
25 | + <RelativeLayout | ||
26 | + android:layout_width="match_parent" | ||
27 | + android:layout_height="wrap_content" | ||
28 | + android:layout_marginBottom="2dip" | ||
29 | + android:layout_marginLeft="7.0dip" | ||
30 | + android:layout_marginRight="7.0dip" | ||
31 | + android:layout_marginTop="2dip" | ||
32 | + android:layout_toLeftOf="@+id/mediacontroller_play_pause" > | ||
33 | + | ||
34 | + <RelativeLayout | ||
35 | + android:layout_width="match_parent" | ||
36 | + android:layout_height="wrap_content" > | ||
37 | + | ||
38 | + <TextView | ||
39 | + android:id="@+id/mediacontroller_time_current" | ||
40 | + style="@style/MediaController_Text" | ||
41 | + android:layout_width="wrap_content" | ||
42 | + android:layout_height="wrap_content" | ||
43 | + android:layout_alignParentLeft="true" | ||
44 | + android:layout_alignParentTop="true" /> | ||
45 | + | ||
46 | + <TextView | ||
47 | + android:id="@+id/mediacontroller_time_total" | ||
48 | + style="@style/MediaController_Text" | ||
49 | + android:layout_width="wrap_content" | ||
50 | + android:layout_height="wrap_content" | ||
51 | + android:layout_alignParentRight="true" | ||
52 | + android:layout_alignParentTop="true" /> | ||
53 | + </RelativeLayout> | ||
54 | + | ||
55 | + <SeekBar | ||
56 | + android:id="@+id/mediacontroller_seekbar" | ||
57 | + style="@style/MediaController_SeekBar" | ||
58 | + android:layout_width="match_parent" | ||
59 | + android:layout_height="wrap_content" | ||
60 | + android:layout_centerVertical="true" | ||
61 | + android:focusable="true" | ||
62 | + android:max="1000" /> | ||
63 | + | ||
64 | + <TextView | ||
65 | + android:id="@+id/mediacontroller_file_name" | ||
66 | + style="@style/MediaController_Text" | ||
67 | + android:layout_width="wrap_content" | ||
68 | + android:layout_height="wrap_content" | ||
69 | + android:layout_alignParentBottom="true" | ||
70 | + android:ellipsize="marquee" | ||
71 | + android:singleLine="true" /> | ||
72 | + </RelativeLayout> | ||
73 | + | ||
74 | +</RelativeLayout> | ||
0 | \ No newline at end of file | 75 | \ No newline at end of file |
VitamioBundle/res/values/strings.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<resources> | ||
3 | + | ||
4 | + <string name="vitamio_name">Vitamio</string> | ||
5 | + <string name="vitamio_init_decoders">Initializing decodersโฆ</string> | ||
6 | + <string name="vitamio_videoview_error_title">Cannot play video</string> | ||
7 | + <string name="vitamio_videoview_error_text_invalid_progressive_playback">Sorry, this video is not valid for streaming to | ||
8 | + this device.</string> | ||
9 | + <string name="vitamio_videoview_error_text_unknown">Sorry, this video cannot be played.</string> | ||
10 | + <string name="vitamio_videoview_error_button">OK</string> | ||
11 | + <string name="mediacontroller_play_pause">Play/Pause</string> | ||
12 | + | ||
13 | +</resources> | ||
0 | \ No newline at end of file | 14 | \ No newline at end of file |
VitamioBundle/res/values/styles.xml
0 โ 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<resources> | ||
3 | + | ||
4 | + <style name="MediaController_SeekBar"> | ||
5 | + <item name="android:minHeight">16dip</item> | ||
6 | + <item name="android:maxHeight">16dip</item> | ||
7 | + <item name="android:progressDrawable">@drawable/mediacontroller_seekbar</item> | ||
8 | + <item name="android:thumb">@drawable/mediacontroller_seekbar_thumb</item> | ||
9 | + </style> | ||
10 | + | ||
11 | + <style name="MediaController_Text"> | ||
12 | + <item name="android:textColor">#ffffffff</item> | ||
13 | + <item name="android:textSize">14sp</item> | ||
14 | + <item name="android:textStyle">bold</item> | ||
15 | + </style> | ||
16 | + | ||
17 | +</resources> | ||
0 | \ No newline at end of file | 18 | \ No newline at end of file |
VitamioBundle/src/io/vov/vitamio/activity/InitActivity.java
0 โ 100644
1 | +/* | ||
2 | + * Copyright (C) 2012 YIXIA.COM | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package io.vov.vitamio.activity; | ||
18 | + | ||
19 | +import io.vov.vitamio.R; | ||
20 | +import io.vov.vitamio.Vitamio; | ||
21 | + | ||
22 | +import java.lang.ref.WeakReference; | ||
23 | + | ||
24 | +import android.app.Activity; | ||
25 | +import android.app.ProgressDialog; | ||
26 | +import android.content.Context; | ||
27 | +import android.content.Intent; | ||
28 | +import android.os.AsyncTask; | ||
29 | +import android.os.Bundle; | ||
30 | +import android.os.Handler; | ||
31 | +import android.os.Message; | ||
32 | +import android.view.WindowManager; | ||
33 | + | ||
34 | +public class InitActivity extends Activity { | ||
35 | + public static final String FROM_ME = "fromVitamioInitActivity"; | ||
36 | + private ProgressDialog mPD; | ||
37 | + private UIHandler uiHandler; | ||
38 | + | ||
39 | + protected void onCreate(Bundle savedInstanceState) { | ||
40 | + super.onCreate(savedInstanceState); | ||
41 | + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); | ||
42 | + uiHandler = new UIHandler(this); | ||
43 | + | ||
44 | + new AsyncTask<Object, Object, Boolean>() { | ||
45 | + @Override | ||
46 | + protected void onPreExecute() { | ||
47 | + mPD = new ProgressDialog(InitActivity.this); | ||
48 | + mPD.setCancelable(false); | ||
49 | + mPD.setMessage(getString(R.string.vitamio_init_decoders)); | ||
50 | + mPD.show(); | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + protected Boolean doInBackground(Object... params) { | ||
55 | + return Vitamio.initialize(InitActivity.this); | ||
56 | + } | ||
57 | + | ||
58 | + @Override | ||
59 | + protected void onPostExecute(Boolean inited) { | ||
60 | + if (inited) { | ||
61 | + uiHandler.sendEmptyMessage(0); | ||
62 | + } | ||
63 | + } | ||
64 | + | ||
65 | + }.execute(); | ||
66 | + } | ||
67 | + | ||
68 | + private static class UIHandler extends Handler { | ||
69 | + private WeakReference<Context> mContext; | ||
70 | + | ||
71 | + public UIHandler(Context c) { | ||
72 | + mContext = new WeakReference<Context>(c); | ||
73 | + } | ||
74 | + | ||
75 | + public void handleMessage(Message msg) { | ||
76 | + InitActivity ctx = (InitActivity) mContext.get(); | ||
77 | + switch (msg.what) { | ||
78 | + case 0: | ||
79 | + ctx.mPD.dismiss(); | ||
80 | + Intent src = ctx.getIntent(); | ||
81 | + Intent i = new Intent(); | ||
82 | + i.setClassName(src.getStringExtra("package"), src.getStringExtra("className")); | ||
83 | + i.setData(src.getData()); | ||
84 | + i.putExtras(src); | ||
85 | + i.putExtra(FROM_ME, true); | ||
86 | + ctx.startActivity(i); | ||
87 | + ctx.finish(); | ||
88 | + break; | ||
89 | + } | ||
90 | + } | ||
91 | + }; | ||
92 | +} |
VitamioBundle/src/io/vov/vitamio/widget/CenterLayout.java
0 โ 100644
1 | +/* | ||
2 | + * Copyright (C) 2012 YIXIA.COM | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package io.vov.vitamio.widget; | ||
18 | + | ||
19 | +import android.content.Context; | ||
20 | +import android.util.AttributeSet; | ||
21 | +import android.view.View; | ||
22 | +import android.view.ViewGroup; | ||
23 | +import android.widget.RemoteViews.RemoteView; | ||
24 | + | ||
25 | +@RemoteView | ||
26 | +public class CenterLayout extends ViewGroup { | ||
27 | + private int mPaddingLeft = 0; | ||
28 | + private int mPaddingRight = 0; | ||
29 | + private int mPaddingTop = 0; | ||
30 | + private int mPaddingBottom = 0; | ||
31 | + private int mWidth, mHeight; | ||
32 | + | ||
33 | + public CenterLayout(Context context) { | ||
34 | + super(context); | ||
35 | + } | ||
36 | + | ||
37 | + public CenterLayout(Context context, AttributeSet attrs) { | ||
38 | + super(context, attrs); | ||
39 | + } | ||
40 | + | ||
41 | + public CenterLayout(Context context, AttributeSet attrs, int defStyle) { | ||
42 | + super(context, attrs, defStyle); | ||
43 | + } | ||
44 | + | ||
45 | + @Override | ||
46 | + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||
47 | + int count = getChildCount(); | ||
48 | + | ||
49 | + int maxHeight = 0; | ||
50 | + int maxWidth = 0; | ||
51 | + | ||
52 | + measureChildren(widthMeasureSpec, heightMeasureSpec); | ||
53 | + | ||
54 | + for (int i = 0; i < count; i++) { | ||
55 | + View child = getChildAt(i); | ||
56 | + if (child.getVisibility() != GONE) { | ||
57 | + int childRight; | ||
58 | + int childBottom; | ||
59 | + | ||
60 | + CenterLayout.LayoutParams lp = (CenterLayout.LayoutParams) child.getLayoutParams(); | ||
61 | + | ||
62 | + childRight = lp.x + child.getMeasuredWidth(); | ||
63 | + childBottom = lp.y + child.getMeasuredHeight(); | ||
64 | + | ||
65 | + maxWidth = Math.max(maxWidth, childRight); | ||
66 | + maxHeight = Math.max(maxHeight, childBottom); | ||
67 | + } | ||
68 | + } | ||
69 | + | ||
70 | + maxWidth += mPaddingLeft + mPaddingRight; | ||
71 | + maxHeight += mPaddingTop + mPaddingBottom; | ||
72 | + | ||
73 | + maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); | ||
74 | + maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); | ||
75 | + | ||
76 | + setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); | ||
77 | + } | ||
78 | + | ||
79 | + @Override | ||
80 | + protected void onLayout(boolean changed, int l, int t, int r, int b) { | ||
81 | + int count = getChildCount(); | ||
82 | + mWidth = getMeasuredWidth(); | ||
83 | + mHeight = getMeasuredHeight(); | ||
84 | + for (int i = 0; i < count; i++) { | ||
85 | + View child = getChildAt(i); | ||
86 | + if (child.getVisibility() != GONE) { | ||
87 | + CenterLayout.LayoutParams lp = (CenterLayout.LayoutParams) child.getLayoutParams(); | ||
88 | + int childLeft = mPaddingLeft + lp.x; | ||
89 | + if (lp.width > 0) | ||
90 | + childLeft += (int) ((mWidth - lp.width) / 2.0); | ||
91 | + else | ||
92 | + childLeft += (int) ((mWidth - child.getMeasuredWidth()) / 2.0); | ||
93 | + int childTop = mPaddingTop + lp.y; | ||
94 | + if (lp.height > 0) | ||
95 | + childTop += (int) ((mHeight - lp.height) / 2.0); | ||
96 | + else | ||
97 | + childTop += (int) ((mHeight - child.getMeasuredHeight()) / 2.0); | ||
98 | + child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); | ||
99 | + } | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | + @Override | ||
104 | + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { | ||
105 | + return p instanceof CenterLayout.LayoutParams; | ||
106 | + } | ||
107 | + | ||
108 | + @Override | ||
109 | + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { | ||
110 | + return new LayoutParams(p); | ||
111 | + } | ||
112 | + | ||
113 | + public static class LayoutParams extends ViewGroup.LayoutParams { | ||
114 | + public int x; | ||
115 | + public int y; | ||
116 | + | ||
117 | + public LayoutParams(int width, int height, int x, int y) { | ||
118 | + super(width, height); | ||
119 | + this.x = x; | ||
120 | + this.y = y; | ||
121 | + } | ||
122 | + | ||
123 | + public LayoutParams(ViewGroup.LayoutParams source) { | ||
124 | + super(source); | ||
125 | + } | ||
126 | + } | ||
127 | +} |
VitamioBundle/src/io/vov/vitamio/widget/MediaController.java
0 โ 100644
1 | +/* | ||
2 | + * Copyright (C) 2006 The Android Open Source Project | ||
3 | + * Copyright (C) 2012 YIXIA.COM | ||
4 | + * | ||
5 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + * you may not use this file except in compliance with the License. | ||
7 | + * You may obtain a copy of the License at | ||
8 | + * | ||
9 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + * | ||
11 | + * Unless required by applicable law or agreed to in writing, software | ||
12 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + * See the License for the specific language governing permissions and | ||
15 | + * limitations under the License. | ||
16 | + */ | ||
17 | + | ||
18 | +package io.vov.vitamio.widget; | ||
19 | + | ||
20 | +import io.vov.utils.Log; | ||
21 | +import io.vov.utils.StringUtils; | ||
22 | +import io.vov.vitamio.R; | ||
23 | +import android.content.Context; | ||
24 | +import android.graphics.Rect; | ||
25 | +import android.media.AudioManager; | ||
26 | +import android.os.Handler; | ||
27 | +import android.os.Message; | ||
28 | +import android.util.AttributeSet; | ||
29 | +import android.view.Gravity; | ||
30 | +import android.view.KeyEvent; | ||
31 | +import android.view.LayoutInflater; | ||
32 | +import android.view.MotionEvent; | ||
33 | +import android.view.View; | ||
34 | +import android.widget.FrameLayout; | ||
35 | +import android.widget.ImageButton; | ||
36 | +import android.widget.PopupWindow; | ||
37 | +import android.widget.ProgressBar; | ||
38 | +import android.widget.SeekBar; | ||
39 | +import android.widget.SeekBar.OnSeekBarChangeListener; | ||
40 | +import android.widget.TextView; | ||
41 | + | ||
42 | +/** | ||
43 | + * A view containing controls for a MediaPlayer. Typically contains the buttons | ||
44 | + * like "Play/Pause" and a progress slider. It takes care of synchronizing the | ||
45 | + * controls with the state of the MediaPlayer. | ||
46 | + * <p> | ||
47 | + * The way to use this class is to a) instantiate it programatically or b) | ||
48 | + * create it in your xml layout. | ||
49 | + * | ||
50 | + * a) The MediaController will create a default set of controls and put them in | ||
51 | + * a window floating above your application. Specifically, the controls will | ||
52 | + * float above the view specified with setAnchorView(). By default, the window | ||
53 | + * will disappear if left idle for three seconds and reappear when the user | ||
54 | + * touches the anchor view. To customize the MediaController's style, layout and | ||
55 | + * controls you should extend MediaController and override the {#link | ||
56 | + * {@link #makeControllerView()} method. | ||
57 | + * | ||
58 | + * b) The MediaController is a FrameLayout, you can put it in your layout xml | ||
59 | + * and get it through {@link #findViewById(int)}. | ||
60 | + * | ||
61 | + * NOTES: In each way, if you want customize the MediaController, the SeekBar's | ||
62 | + * id must be mediacontroller_progress, the Play/Pause's must be | ||
63 | + * mediacontroller_pause, current time's must be mediacontroller_time_current, | ||
64 | + * total time's must be mediacontroller_time_total, file name's must be | ||
65 | + * mediacontroller_file_name. And your resources must have a pause_button | ||
66 | + * drawable and a play_button drawable. | ||
67 | + * <p> | ||
68 | + * Functions like show() and hide() have no effect when MediaController is | ||
69 | + * created in an xml layout. | ||
70 | + */ | ||
71 | +public class MediaController extends FrameLayout { | ||
72 | + private MediaPlayerControl mPlayer; | ||
73 | + private Context mContext; | ||
74 | + private PopupWindow mWindow; | ||
75 | + private int mAnimStyle; | ||
76 | + private View mAnchor; | ||
77 | + private View mRoot; | ||
78 | + private ProgressBar mProgress; | ||
79 | + private TextView mEndTime, mCurrentTime; | ||
80 | + private TextView mFileName; | ||
81 | + private OutlineTextView mInfoView; | ||
82 | + private String mTitle; | ||
83 | + private long mDuration; | ||
84 | + private boolean mShowing; | ||
85 | + private boolean mDragging; | ||
86 | + private boolean mInstantSeeking = true; | ||
87 | + private static final int sDefaultTimeout = 3000; | ||
88 | + private static final int FADE_OUT = 1; | ||
89 | + private static final int SHOW_PROGRESS = 2; | ||
90 | + private boolean mFromXml = false; | ||
91 | + private ImageButton mPauseButton; | ||
92 | + | ||
93 | + private AudioManager mAM; | ||
94 | + | ||
95 | + public MediaController(Context context, AttributeSet attrs) { | ||
96 | + super(context, attrs); | ||
97 | + mRoot = this; | ||
98 | + mFromXml = true; | ||
99 | + initController(context); | ||
100 | + } | ||
101 | + | ||
102 | + public MediaController(Context context) { | ||
103 | + super(context); | ||
104 | + if (!mFromXml && initController(context)) | ||
105 | + initFloatingWindow(); | ||
106 | + } | ||
107 | + | ||
108 | + private boolean initController(Context context) { | ||
109 | + mContext = context; | ||
110 | + mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); | ||
111 | + return true; | ||
112 | + } | ||
113 | + | ||
114 | + @Override | ||
115 | + public void onFinishInflate() { | ||
116 | + if (mRoot != null) | ||
117 | + initControllerView(mRoot); | ||
118 | + } | ||
119 | + | ||
120 | + private void initFloatingWindow() { | ||
121 | + mWindow = new PopupWindow(mContext); | ||
122 | + mWindow.setFocusable(false); | ||
123 | + mWindow.setBackgroundDrawable(null); | ||
124 | + mWindow.setOutsideTouchable(true); | ||
125 | + mAnimStyle = android.R.style.Animation; | ||
126 | + } | ||
127 | + | ||
128 | + /** | ||
129 | + * Set the view that acts as the anchor for the control view. This can for | ||
130 | + * example be a VideoView, or your Activity's main view. | ||
131 | + * | ||
132 | + * @param view | ||
133 | + * The view to which to anchor the controller when it is visible. | ||
134 | + */ | ||
135 | + public void setAnchorView(View view) { | ||
136 | + mAnchor = view; | ||
137 | + if (!mFromXml) { | ||
138 | + removeAllViews(); | ||
139 | + mRoot = makeControllerView(); | ||
140 | + mWindow.setContentView(mRoot); | ||
141 | + mWindow.setWidth(LayoutParams.MATCH_PARENT); | ||
142 | + mWindow.setHeight(LayoutParams.WRAP_CONTENT); | ||
143 | + } | ||
144 | + initControllerView(mRoot); | ||
145 | + } | ||
146 | + | ||
147 | + /** | ||
148 | + * Create the view that holds the widgets that control playback. Derived | ||
149 | + * classes can override this to create their own. | ||
150 | + * | ||
151 | + * @return The controller view. | ||
152 | + */ | ||
153 | + protected View makeControllerView() { | ||
154 | + return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.mediacontroller, this); | ||
155 | + } | ||
156 | + | ||
157 | + private void initControllerView(View v) { | ||
158 | + mPauseButton = (ImageButton) v.findViewById(R.id.mediacontroller_play_pause); | ||
159 | + if (mPauseButton != null) { | ||
160 | + mPauseButton.requestFocus(); | ||
161 | + mPauseButton.setOnClickListener(mPauseListener); | ||
162 | + } | ||
163 | + | ||
164 | + mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_seekbar); | ||
165 | + if (mProgress != null) { | ||
166 | + if (mProgress instanceof SeekBar) { | ||
167 | + SeekBar seeker = (SeekBar) mProgress; | ||
168 | + seeker.setOnSeekBarChangeListener(mSeekListener); | ||
169 | + seeker.setThumbOffset(1); | ||
170 | + } | ||
171 | + mProgress.setMax(1000); | ||
172 | + } | ||
173 | + | ||
174 | + mEndTime = (TextView) v.findViewById(R.id.mediacontroller_time_total); | ||
175 | + mCurrentTime = (TextView) v.findViewById(R.id.mediacontroller_time_current); | ||
176 | + mFileName = (TextView) v.findViewById(R.id.mediacontroller_file_name); | ||
177 | + if (mFileName != null) | ||
178 | + mFileName.setText(mTitle); | ||
179 | + } | ||
180 | + | ||
181 | + public void setMediaPlayer(MediaPlayerControl player) { | ||
182 | + mPlayer = player; | ||
183 | + updatePausePlay(); | ||
184 | + } | ||
185 | + | ||
186 | + /** | ||
187 | + * Control the action when the seekbar dragged by user | ||
188 | + * | ||
189 | + * @param seekWhenDragging | ||
190 | + * True the media will seek periodically | ||
191 | + */ | ||
192 | + public void setInstantSeeking(boolean seekWhenDragging) { | ||
193 | + mInstantSeeking = seekWhenDragging; | ||
194 | + } | ||
195 | + | ||
196 | + public void show() { | ||
197 | + show(sDefaultTimeout); | ||
198 | + } | ||
199 | + | ||
200 | + /** | ||
201 | + * Set the content of the file_name TextView | ||
202 | + * | ||
203 | + * @param name | ||
204 | + */ | ||
205 | + public void setFileName(String name) { | ||
206 | + mTitle = name; | ||
207 | + if (mFileName != null) | ||
208 | + mFileName.setText(mTitle); | ||
209 | + } | ||
210 | + | ||
211 | + /** | ||
212 | + * Set the View to hold some information when interact with the | ||
213 | + * MediaController | ||
214 | + * | ||
215 | + * @param v | ||
216 | + */ | ||
217 | + public void setInfoView(OutlineTextView v) { | ||
218 | + mInfoView = v; | ||
219 | + } | ||
220 | + | ||
221 | + private void disableUnsupportedButtons() { | ||
222 | + try { | ||
223 | + if (mPauseButton != null && !mPlayer.canPause()) | ||
224 | + mPauseButton.setEnabled(false); | ||
225 | + } catch (IncompatibleClassChangeError ex) { | ||
226 | + } | ||
227 | + } | ||
228 | + | ||
229 | + /** | ||
230 | + * <p> | ||
231 | + * Change the animation style resource for this controller. | ||
232 | + * </p> | ||
233 | + * | ||
234 | + * <p> | ||
235 | + * If the controller is showing, calling this method will take effect only | ||
236 | + * the next time the controller is shown. | ||
237 | + * </p> | ||
238 | + * | ||
239 | + * @param animationStyle | ||
240 | + * animation style to use when the controller appears and | ||
241 | + * disappears. Set to -1 for the default animation, 0 for no | ||
242 | + * animation, or a resource identifier for an explicit animation. | ||
243 | + * | ||
244 | + */ | ||
245 | + public void setAnimationStyle(int animationStyle) { | ||
246 | + mAnimStyle = animationStyle; | ||
247 | + } | ||
248 | + | ||
249 | + /** | ||
250 | + * Show the controller on screen. It will go away automatically after | ||
251 | + * 'timeout' milliseconds of inactivity. | ||
252 | + * | ||
253 | + * @param timeout | ||
254 | + * The timeout in milliseconds. Use 0 to show the controller | ||
255 | + * until hide() is called. | ||
256 | + */ | ||
257 | + public void show(int timeout) { | ||
258 | + if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) { | ||
259 | + if (mPauseButton != null) | ||
260 | + mPauseButton.requestFocus(); | ||
261 | + disableUnsupportedButtons(); | ||
262 | + | ||
263 | + if (mFromXml) { | ||
264 | + setVisibility(View.VISIBLE); | ||
265 | + } else { | ||
266 | + int[] location = new int[2]; | ||
267 | + | ||
268 | + mAnchor.getLocationOnScreen(location); | ||
269 | + Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); | ||
270 | + | ||
271 | + mWindow.setAnimationStyle(mAnimStyle); | ||
272 | + mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom); | ||
273 | + } | ||
274 | + mShowing = true; | ||
275 | + if (mShownListener != null) | ||
276 | + mShownListener.onShown(); | ||
277 | + } | ||
278 | + updatePausePlay(); | ||
279 | + mHandler.sendEmptyMessage(SHOW_PROGRESS); | ||
280 | + | ||
281 | + if (timeout != 0) { | ||
282 | + mHandler.removeMessages(FADE_OUT); | ||
283 | + mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout); | ||
284 | + } | ||
285 | + } | ||
286 | + | ||
287 | + public boolean isShowing() { | ||
288 | + return mShowing; | ||
289 | + } | ||
290 | + | ||
291 | + public void hide() { | ||
292 | + if (mAnchor == null) | ||
293 | + return; | ||
294 | + | ||
295 | + if (mShowing) { | ||
296 | + try { | ||
297 | + mHandler.removeMessages(SHOW_PROGRESS); | ||
298 | + if (mFromXml) | ||
299 | + setVisibility(View.GONE); | ||
300 | + else | ||
301 | + mWindow.dismiss(); | ||
302 | + } catch (IllegalArgumentException ex) { | ||
303 | + Log.d("MediaController already removed"); | ||
304 | + } | ||
305 | + mShowing = false; | ||
306 | + if (mHiddenListener != null) | ||
307 | + mHiddenListener.onHidden(); | ||
308 | + } | ||
309 | + } | ||
310 | + | ||
311 | + public interface OnShownListener { | ||
312 | + public void onShown(); | ||
313 | + } | ||
314 | + | ||
315 | + private OnShownListener mShownListener; | ||
316 | + | ||
317 | + public void setOnShownListener(OnShownListener l) { | ||
318 | + mShownListener = l; | ||
319 | + } | ||
320 | + | ||
321 | + public interface OnHiddenListener { | ||
322 | + public void onHidden(); | ||
323 | + } | ||
324 | + | ||
325 | + private OnHiddenListener mHiddenListener; | ||
326 | + | ||
327 | + public void setOnHiddenListener(OnHiddenListener l) { | ||
328 | + mHiddenListener = l; | ||
329 | + } | ||
330 | + | ||
331 | + private Handler mHandler = new Handler() { | ||
332 | + @Override | ||
333 | + public void handleMessage(Message msg) { | ||
334 | + long pos; | ||
335 | + switch (msg.what) { | ||
336 | + case FADE_OUT: | ||
337 | + hide(); | ||
338 | + break; | ||
339 | + case SHOW_PROGRESS: | ||
340 | + pos = setProgress(); | ||
341 | + if (!mDragging && mShowing) { | ||
342 | + msg = obtainMessage(SHOW_PROGRESS); | ||
343 | + sendMessageDelayed(msg, 1000 - (pos % 1000)); | ||
344 | + updatePausePlay(); | ||
345 | + } | ||
346 | + break; | ||
347 | + } | ||
348 | + } | ||
349 | + }; | ||
350 | + | ||
351 | + private long setProgress() { | ||
352 | + if (mPlayer == null || mDragging) | ||
353 | + return 0; | ||
354 | + | ||
355 | + long position = mPlayer.getCurrentPosition(); | ||
356 | + long duration = mPlayer.getDuration(); | ||
357 | + if (mProgress != null) { | ||
358 | + if (duration > 0) { | ||
359 | + long pos = 1000L * position / duration; | ||
360 | + mProgress.setProgress((int) pos); | ||
361 | + } | ||
362 | + int percent = mPlayer.getBufferPercentage(); | ||
363 | + mProgress.setSecondaryProgress(percent * 10); | ||
364 | + } | ||
365 | + | ||
366 | + mDuration = duration; | ||
367 | + | ||
368 | + if (mEndTime != null) | ||
369 | + mEndTime.setText(StringUtils.generateTime(mDuration)); | ||
370 | + if (mCurrentTime != null) | ||
371 | + mCurrentTime.setText(StringUtils.generateTime(position)); | ||
372 | + | ||
373 | + return position; | ||
374 | + } | ||
375 | + | ||
376 | + @Override | ||
377 | + public boolean onTouchEvent(MotionEvent event) { | ||
378 | + show(sDefaultTimeout); | ||
379 | + return true; | ||
380 | + } | ||
381 | + | ||
382 | + @Override | ||
383 | + public boolean onTrackballEvent(MotionEvent ev) { | ||
384 | + show(sDefaultTimeout); | ||
385 | + return false; | ||
386 | + } | ||
387 | + | ||
388 | + @Override | ||
389 | + public boolean dispatchKeyEvent(KeyEvent event) { | ||
390 | + int keyCode = event.getKeyCode(); | ||
391 | + if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) { | ||
392 | + doPauseResume(); | ||
393 | + show(sDefaultTimeout); | ||
394 | + if (mPauseButton != null) | ||
395 | + mPauseButton.requestFocus(); | ||
396 | + return true; | ||
397 | + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) { | ||
398 | + if (mPlayer.isPlaying()) { | ||
399 | + mPlayer.pause(); | ||
400 | + updatePausePlay(); | ||
401 | + } | ||
402 | + return true; | ||
403 | + } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { | ||
404 | + hide(); | ||
405 | + return true; | ||
406 | + } else { | ||
407 | + show(sDefaultTimeout); | ||
408 | + } | ||
409 | + return super.dispatchKeyEvent(event); | ||
410 | + } | ||
411 | + | ||
412 | + private View.OnClickListener mPauseListener = new View.OnClickListener() { | ||
413 | + public void onClick(View v) { | ||
414 | + doPauseResume(); | ||
415 | + show(sDefaultTimeout); | ||
416 | + } | ||
417 | + }; | ||
418 | + | ||
419 | + private void updatePausePlay() { | ||
420 | + if (mRoot == null || mPauseButton == null) | ||
421 | + return; | ||
422 | + | ||
423 | + if (mPlayer.isPlaying()) | ||
424 | + mPauseButton.setImageResource(R.drawable.mediacontroller_pause_button); | ||
425 | + else | ||
426 | + mPauseButton.setImageResource(R.drawable.mediacontroller_play_button); | ||
427 | + } | ||
428 | + | ||
429 | + private void doPauseResume() { | ||
430 | + if (mPlayer.isPlaying()) | ||
431 | + mPlayer.pause(); | ||
432 | + else | ||
433 | + mPlayer.start(); | ||
434 | + updatePausePlay(); | ||
435 | + } | ||
436 | + | ||
437 | + private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { | ||
438 | + public void onStartTrackingTouch(SeekBar bar) { | ||
439 | + mDragging = true; | ||
440 | + show(3600000); | ||
441 | + mHandler.removeMessages(SHOW_PROGRESS); | ||
442 | + if (mInstantSeeking) | ||
443 | + mAM.setStreamMute(AudioManager.STREAM_MUSIC, true); | ||
444 | + if (mInfoView != null) { | ||
445 | + mInfoView.setText(""); | ||
446 | + mInfoView.setVisibility(View.VISIBLE); | ||
447 | + } | ||
448 | + } | ||
449 | + | ||
450 | + public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { | ||
451 | + if (!fromuser) | ||
452 | + return; | ||
453 | + | ||
454 | + long newposition = (mDuration * progress) / 1000; | ||
455 | + String time = StringUtils.generateTime(newposition); | ||
456 | + if (mInstantSeeking) | ||
457 | + mPlayer.seekTo(newposition); | ||
458 | + if (mInfoView != null) | ||
459 | + mInfoView.setText(time); | ||
460 | + if (mCurrentTime != null) | ||
461 | + mCurrentTime.setText(time); | ||
462 | + } | ||
463 | + | ||
464 | + public void onStopTrackingTouch(SeekBar bar) { | ||
465 | + if (!mInstantSeeking) | ||
466 | + mPlayer.seekTo((mDuration * bar.getProgress()) / 1000); | ||
467 | + if (mInfoView != null) { | ||
468 | + mInfoView.setText(""); | ||
469 | + mInfoView.setVisibility(View.GONE); | ||
470 | + } | ||
471 | + show(sDefaultTimeout); | ||
472 | + mHandler.removeMessages(SHOW_PROGRESS); | ||
473 | + mAM.setStreamMute(AudioManager.STREAM_MUSIC, false); | ||
474 | + mDragging = false; | ||
475 | + mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000); | ||
476 | + } | ||
477 | + }; | ||
478 | + | ||
479 | + @Override | ||
480 | + public void setEnabled(boolean enabled) { | ||
481 | + if (mPauseButton != null) | ||
482 | + mPauseButton.setEnabled(enabled); | ||
483 | + if (mProgress != null) | ||
484 | + mProgress.setEnabled(enabled); | ||
485 | + disableUnsupportedButtons(); | ||
486 | + super.setEnabled(enabled); | ||
487 | + } | ||
488 | + | ||
489 | + public interface MediaPlayerControl { | ||
490 | + void start(); | ||
491 | + | ||
492 | + void pause(); | ||
493 | + | ||
494 | + long getDuration(); | ||
495 | + | ||
496 | + long getCurrentPosition(); | ||
497 | + | ||
498 | + void seekTo(long pos); | ||
499 | + | ||
500 | + boolean isPlaying(); | ||
501 | + | ||
502 | + int getBufferPercentage(); | ||
503 | + | ||
504 | + boolean canPause(); | ||
505 | + | ||
506 | + boolean canSeekBackward(); | ||
507 | + | ||
508 | + boolean canSeekForward(); | ||
509 | + } | ||
510 | + | ||
511 | +} |
VitamioBundle/src/io/vov/vitamio/widget/OutlineTextView.java
0 โ 100644
1 | +/* | ||
2 | + * Copyright (C) 2011 Cedric Fung (wolfplanet@gmail.com) | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package io.vov.vitamio.widget; | ||
18 | + | ||
19 | +import android.annotation.SuppressLint; | ||
20 | +import android.content.Context; | ||
21 | +import android.graphics.Canvas; | ||
22 | +import android.graphics.Paint; | ||
23 | +import android.graphics.Typeface; | ||
24 | +import android.text.Layout; | ||
25 | +import android.text.StaticLayout; | ||
26 | +import android.text.TextPaint; | ||
27 | +import android.util.AttributeSet; | ||
28 | +import android.widget.TextView; | ||
29 | + | ||
30 | +/** | ||
31 | + * Display text with border, use the same XML attrs as | ||
32 | + * {@link android.widget.TextView}, except that {@link OutlineTextView} will | ||
33 | + * transform the shadow to border | ||
34 | + */ | ||
35 | +@SuppressLint("DrawAllocation") | ||
36 | +public class OutlineTextView extends TextView { | ||
37 | + public OutlineTextView(Context context) { | ||
38 | + super(context); | ||
39 | + initPaint(); | ||
40 | + } | ||
41 | + | ||
42 | + public OutlineTextView(Context context, AttributeSet attrs) { | ||
43 | + super(context, attrs); | ||
44 | + initPaint(); | ||
45 | + } | ||
46 | + | ||
47 | + public OutlineTextView(Context context, AttributeSet attrs, int defStyle) { | ||
48 | + super(context, attrs, defStyle); | ||
49 | + initPaint(); | ||
50 | + } | ||
51 | + | ||
52 | + private void initPaint() { | ||
53 | + mTextPaint = new TextPaint(); | ||
54 | + mTextPaint.setAntiAlias(true); | ||
55 | + mTextPaint.setTextSize(getTextSize()); | ||
56 | + mTextPaint.setColor(mColor); | ||
57 | + mTextPaint.setStyle(Paint.Style.FILL); | ||
58 | + mTextPaint.setTypeface(getTypeface()); | ||
59 | + | ||
60 | + mTextPaintOutline = new TextPaint(); | ||
61 | + mTextPaintOutline.setAntiAlias(true); | ||
62 | + mTextPaintOutline.setTextSize(getTextSize()); | ||
63 | + mTextPaintOutline.setColor(mBorderColor); | ||
64 | + mTextPaintOutline.setStyle(Paint.Style.STROKE); | ||
65 | + mTextPaintOutline.setTypeface(getTypeface()); | ||
66 | + mTextPaintOutline.setStrokeWidth(mBorderSize); | ||
67 | + } | ||
68 | + | ||
69 | + public void setText(String text) { | ||
70 | + super.setText(text); | ||
71 | + mText = text.toString(); | ||
72 | + requestLayout(); | ||
73 | + invalidate(); | ||
74 | + } | ||
75 | + | ||
76 | + public void setTextSize(float size) { | ||
77 | + super.setTextSize(size); | ||
78 | + requestLayout(); | ||
79 | + invalidate(); | ||
80 | + initPaint(); | ||
81 | + } | ||
82 | + | ||
83 | + public void setTextColor(int color) { | ||
84 | + super.setTextColor(color); | ||
85 | + mColor = color; | ||
86 | + invalidate(); | ||
87 | + initPaint(); | ||
88 | + } | ||
89 | + | ||
90 | + public void setShadowLayer(float radius, float dx, float dy, int color) { | ||
91 | + super.setShadowLayer(radius, dx, dy, color); | ||
92 | + mBorderSize = radius; | ||
93 | + mBorderColor = color; | ||
94 | + requestLayout(); | ||
95 | + invalidate(); | ||
96 | + initPaint(); | ||
97 | + } | ||
98 | + | ||
99 | + public void setTypeface(Typeface tf, int style) { | ||
100 | + super.setTypeface(tf, style); | ||
101 | + requestLayout(); | ||
102 | + invalidate(); | ||
103 | + initPaint(); | ||
104 | + } | ||
105 | + | ||
106 | + public void setTypeface(Typeface tf) { | ||
107 | + super.setTypeface(tf); | ||
108 | + requestLayout(); | ||
109 | + invalidate(); | ||
110 | + initPaint(); | ||
111 | + } | ||
112 | + | ||
113 | + @Override | ||
114 | + protected void onDraw(Canvas canvas) { | ||
115 | + Layout layout = new StaticLayout(getText(), mTextPaintOutline, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad); | ||
116 | + layout.draw(canvas); | ||
117 | + layout = new StaticLayout(getText(), mTextPaint, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad); | ||
118 | + layout.draw(canvas); | ||
119 | + } | ||
120 | + | ||
121 | + @Override | ||
122 | + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||
123 | + Layout layout = new StaticLayout(getText(), mTextPaintOutline, measureWidth(widthMeasureSpec), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad); | ||
124 | + int ex = (int) (mBorderSize * 2 + 1); | ||
125 | + setMeasuredDimension(measureWidth(widthMeasureSpec) + ex, measureHeight(heightMeasureSpec) * layout.getLineCount() + ex); | ||
126 | + } | ||
127 | + | ||
128 | + private int measureWidth(int measureSpec) { | ||
129 | + int result = 0; | ||
130 | + int specMode = MeasureSpec.getMode(measureSpec); | ||
131 | + int specSize = MeasureSpec.getSize(measureSpec); | ||
132 | + | ||
133 | + if (specMode == MeasureSpec.EXACTLY) { | ||
134 | + result = specSize; | ||
135 | + } else { | ||
136 | + result = (int) mTextPaintOutline.measureText(mText) + getPaddingLeft() + getPaddingRight(); | ||
137 | + if (specMode == MeasureSpec.AT_MOST) { | ||
138 | + result = Math.min(result, specSize); | ||
139 | + } | ||
140 | + } | ||
141 | + | ||
142 | + return result; | ||
143 | + } | ||
144 | + | ||
145 | + private int measureHeight(int measureSpec) { | ||
146 | + int result = 0; | ||
147 | + int specMode = MeasureSpec.getMode(measureSpec); | ||
148 | + int specSize = MeasureSpec.getSize(measureSpec); | ||
149 | + | ||
150 | + mAscent = (int) mTextPaintOutline.ascent(); | ||
151 | + if (specMode == MeasureSpec.EXACTLY) { | ||
152 | + result = specSize; | ||
153 | + } else { | ||
154 | + result = (int) (-mAscent + mTextPaintOutline.descent()) + getPaddingTop() + getPaddingBottom(); | ||
155 | + if (specMode == MeasureSpec.AT_MOST) { | ||
156 | + result = Math.min(result, specSize); | ||
157 | + } | ||
158 | + } | ||
159 | + return result; | ||
160 | + } | ||
161 | + | ||
162 | + private TextPaint mTextPaint; | ||
163 | + private TextPaint mTextPaintOutline; | ||
164 | + private String mText = ""; | ||
165 | + private int mAscent = 0; | ||
166 | + private float mBorderSize; | ||
167 | + private int mBorderColor; | ||
168 | + private int mColor; | ||
169 | + private float mSpacingMult = 1.0f; | ||
170 | + private float mSpacingAdd = 0; | ||
171 | + private boolean mIncludePad = true; | ||
172 | +} | ||
0 | \ No newline at end of file | 173 | \ No newline at end of file |
VitamioBundle/src/io/vov/vitamio/widget/VideoView.java
0 โ 100644
1 | +/* | ||
2 | + * Copyright (C) 2006 The Android Open Source Project | ||
3 | + * Copyright (C) 2012 YIXIA.COM | ||
4 | + * | ||
5 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + * you may not use this file except in compliance with the License. | ||
7 | + * You may obtain a copy of the License at | ||
8 | + * | ||
9 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + * | ||
11 | + * Unless required by applicable law or agreed to in writing, software | ||
12 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + * See the License for the specific language governing permissions and | ||
15 | + * limitations under the License. | ||
16 | + */ | ||
17 | + | ||
18 | +package io.vov.vitamio.widget; | ||
19 | + | ||
20 | +import io.vov.utils.Log; | ||
21 | +import io.vov.vitamio.MediaPlayer; | ||
22 | +import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener; | ||
23 | +import io.vov.vitamio.MediaPlayer.OnCompletionListener; | ||
24 | +import io.vov.vitamio.MediaPlayer.OnErrorListener; | ||
25 | +import io.vov.vitamio.MediaPlayer.OnInfoListener; | ||
26 | +import io.vov.vitamio.MediaPlayer.OnPreparedListener; | ||
27 | +import io.vov.vitamio.MediaPlayer.OnSeekCompleteListener; | ||
28 | +import io.vov.vitamio.MediaPlayer.OnSubtitleUpdateListener; | ||
29 | +import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener; | ||
30 | +import io.vov.vitamio.R; | ||
31 | + | ||
32 | +import java.io.IOException; | ||
33 | +import java.util.HashMap; | ||
34 | +import java.util.List; | ||
35 | + | ||
36 | +import android.app.Activity; | ||
37 | +import android.app.AlertDialog; | ||
38 | +import android.content.Context; | ||
39 | +import android.content.DialogInterface; | ||
40 | +import android.content.Intent; | ||
41 | +import android.media.AudioManager; | ||
42 | +import android.net.Uri; | ||
43 | +import android.util.AttributeSet; | ||
44 | +import android.util.DisplayMetrics; | ||
45 | +import android.view.KeyEvent; | ||
46 | +import android.view.MotionEvent; | ||
47 | +import android.view.SurfaceHolder; | ||
48 | +import android.view.SurfaceView; | ||
49 | +import android.view.View; | ||
50 | +import android.view.ViewGroup.LayoutParams; | ||
51 | + | ||
52 | +/** | ||
53 | + * Displays a video file. The VideoView class can load images from various | ||
54 | + * sources (such as resources or content providers), takes care of computing its | ||
55 | + * measurement from the video so that it can be used in any layout manager, and | ||
56 | + * provides various display options such as scaling and tinting. | ||
57 | + * | ||
58 | + * VideoView also provide many wrapper methods for | ||
59 | + * {@link io.vov.vitamio.MediaPlayer}, such as {@link #getVideoWidth()}, | ||
60 | + * {@link #setSubShown(boolean)} | ||
61 | + */ | ||
62 | +public class VideoView extends SurfaceView implements MediaController.MediaPlayerControl { | ||
63 | + private Uri mUri; | ||
64 | + private long mDuration; | ||
65 | + | ||
66 | + private static final int STATE_ERROR = -1; | ||
67 | + private static final int STATE_IDLE = 0; | ||
68 | + private static final int STATE_PREPARING = 1; | ||
69 | + private static final int STATE_PREPARED = 2; | ||
70 | + private static final int STATE_PLAYING = 3; | ||
71 | + private static final int STATE_PAUSED = 4; | ||
72 | + private static final int STATE_PLAYBACK_COMPLETED = 5; | ||
73 | + private static final int STATE_SUSPEND = 6; | ||
74 | + private static final int STATE_RESUME = 7; | ||
75 | + private static final int STATE_SUSPEND_UNSUPPORTED = 8; | ||
76 | + | ||
77 | + private int mCurrentState = STATE_IDLE; | ||
78 | + private int mTargetState = STATE_IDLE; | ||
79 | + | ||
80 | + private float mAspectRatio = 0; | ||
81 | + private int mVideoLayout = VIDEO_LAYOUT_SCALE; | ||
82 | + public static final int VIDEO_LAYOUT_ORIGIN = 0; | ||
83 | + public static final int VIDEO_LAYOUT_SCALE = 1; | ||
84 | + public static final int VIDEO_LAYOUT_STRETCH = 2; | ||
85 | + public static final int VIDEO_LAYOUT_ZOOM = 3; | ||
86 | + | ||
87 | + private SurfaceHolder mSurfaceHolder = null; | ||
88 | + private MediaPlayer mMediaPlayer = null; | ||
89 | + private int mVideoWidth; | ||
90 | + private int mVideoHeight; | ||
91 | + private float mVideoAspectRatio; | ||
92 | + private int mSurfaceWidth; | ||
93 | + private int mSurfaceHeight; | ||
94 | + private MediaController mMediaController; | ||
95 | + private OnCompletionListener mOnCompletionListener; | ||
96 | + private OnPreparedListener mOnPreparedListener; | ||
97 | + private OnErrorListener mOnErrorListener; | ||
98 | + private OnSeekCompleteListener mOnSeekCompleteListener; | ||
99 | + private OnSubtitleUpdateListener mOnSubtitleUpdateListener; | ||
100 | + private OnInfoListener mOnInfoListener; | ||
101 | + private OnBufferingUpdateListener mOnBufferingUpdateListener; | ||
102 | + private int mCurrentBufferPercentage; | ||
103 | + private long mSeekWhenPrepared; | ||
104 | + private boolean mCanPause = true; | ||
105 | + private boolean mCanSeekBack = true; | ||
106 | + private boolean mCanSeekForward = true; | ||
107 | + private Context mContext; | ||
108 | + | ||
109 | + public VideoView(Context context) { | ||
110 | + super(context); | ||
111 | + initVideoView(context); | ||
112 | + } | ||
113 | + | ||
114 | + public VideoView(Context context, AttributeSet attrs) { | ||
115 | + this(context, attrs, 0); | ||
116 | + } | ||
117 | + | ||
118 | + public VideoView(Context context, AttributeSet attrs, int defStyle) { | ||
119 | + super(context, attrs, defStyle); | ||
120 | + initVideoView(context); | ||
121 | + } | ||
122 | + | ||
123 | + @Override | ||
124 | + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||
125 | + int width = getDefaultSize(mVideoWidth, widthMeasureSpec); | ||
126 | + int height = getDefaultSize(mVideoHeight, heightMeasureSpec); | ||
127 | + setMeasuredDimension(width, height); | ||
128 | + } | ||
129 | + | ||
130 | + /** | ||
131 | + * Set the display options | ||
132 | + * | ||
133 | + * @param layout | ||
134 | + * <ul> | ||
135 | + * <li>{@link #VIDEO_LAYOUT_ORIGIN} | ||
136 | + * <li>{@link #VIDEO_LAYOUT_SCALE} | ||
137 | + * <li>{@link #VIDEO_LAYOUT_STRETCH} | ||
138 | + * <li>{@link #VIDEO_LAYOUT_ZOOM} | ||
139 | + * </ul> | ||
140 | + * @param aspectRatio | ||
141 | + * video aspect ratio, will audo detect if 0. | ||
142 | + */ | ||
143 | + public void setVideoLayout(int layout, float aspectRatio) { | ||
144 | + LayoutParams lp = getLayoutParams(); | ||
145 | + DisplayMetrics disp = mContext.getResources().getDisplayMetrics(); | ||
146 | + int windowWidth = disp.widthPixels, windowHeight = disp.heightPixels; | ||
147 | + float windowRatio = windowWidth / (float) windowHeight; | ||
148 | + float videoRatio = aspectRatio <= 0.01f ? mVideoAspectRatio : aspectRatio; | ||
149 | + mSurfaceHeight = mVideoHeight; | ||
150 | + mSurfaceWidth = mVideoWidth; | ||
151 | + if (VIDEO_LAYOUT_ORIGIN == layout && mSurfaceWidth < windowWidth && mSurfaceHeight < windowHeight) { | ||
152 | + lp.width = (int) (mSurfaceHeight * videoRatio); | ||
153 | + lp.height = mSurfaceHeight; | ||
154 | + } else if (layout == VIDEO_LAYOUT_ZOOM) { | ||
155 | + lp.width = windowRatio > videoRatio ? windowWidth : (int) (videoRatio * windowHeight); | ||
156 | + lp.height = windowRatio < videoRatio ? windowHeight : (int) (windowWidth / videoRatio); | ||
157 | + } else { | ||
158 | + boolean full = layout == VIDEO_LAYOUT_STRETCH; | ||
159 | + lp.width = (full || windowRatio < videoRatio) ? windowWidth : (int) (videoRatio * windowHeight); | ||
160 | + lp.height = (full || windowRatio > videoRatio) ? windowHeight : (int) (windowWidth / videoRatio); | ||
161 | + } | ||
162 | + setLayoutParams(lp); | ||
163 | + getHolder().setFixedSize(mSurfaceWidth, mSurfaceHeight); | ||
164 | + Log.d("VIDEO: %dx%dx%f, Surface: %dx%d, LP: %dx%d, Window: %dx%dx%f", mVideoWidth, mVideoHeight, mVideoAspectRatio, mSurfaceWidth, mSurfaceHeight, lp.width, lp.height, windowWidth, windowHeight, windowRatio); | ||
165 | + mVideoLayout = layout; | ||
166 | + mAspectRatio = aspectRatio; | ||
167 | + } | ||
168 | + | ||
169 | + private void initVideoView(Context ctx) { | ||
170 | + mContext = ctx; | ||
171 | + mVideoWidth = 0; | ||
172 | + mVideoHeight = 0; | ||
173 | + getHolder().addCallback(mSHCallback); | ||
174 | + setFocusable(true); | ||
175 | + setFocusableInTouchMode(true); | ||
176 | + requestFocus(); | ||
177 | + mCurrentState = STATE_IDLE; | ||
178 | + mTargetState = STATE_IDLE; | ||
179 | + if (ctx instanceof Activity) | ||
180 | + ((Activity) ctx).setVolumeControlStream(AudioManager.STREAM_MUSIC); | ||
181 | + } | ||
182 | + | ||
183 | + public boolean isValid() { | ||
184 | + return (mSurfaceHolder != null && mSurfaceHolder.getSurface().isValid()); | ||
185 | + } | ||
186 | + | ||
187 | + public void setVideoPath(String path) { | ||
188 | + setVideoURI(Uri.parse(path)); | ||
189 | + } | ||
190 | + | ||
191 | + public void setVideoURI(Uri uri) { | ||
192 | + mUri = uri; | ||
193 | + mSeekWhenPrepared = 0; | ||
194 | + openVideo(); | ||
195 | + requestLayout(); | ||
196 | + invalidate(); | ||
197 | + } | ||
198 | + | ||
199 | + public void stopPlayback() { | ||
200 | + if (mMediaPlayer != null) { | ||
201 | + mMediaPlayer.stop(); | ||
202 | + mMediaPlayer.release(); | ||
203 | + mMediaPlayer = null; | ||
204 | + mCurrentState = STATE_IDLE; | ||
205 | + mTargetState = STATE_IDLE; | ||
206 | + } | ||
207 | + } | ||
208 | + | ||
209 | + private void openVideo() { | ||
210 | + if (mUri == null || mSurfaceHolder == null) | ||
211 | + return; | ||
212 | + | ||
213 | + Intent i = new Intent("com.android.music.musicservicecommand"); | ||
214 | + i.putExtra("command", "pause"); | ||
215 | + mContext.sendBroadcast(i); | ||
216 | + | ||
217 | + release(false); | ||
218 | + try { | ||
219 | + mDuration = -1; | ||
220 | + mCurrentBufferPercentage = 0; | ||
221 | + mMediaPlayer = new MediaPlayer(mContext); | ||
222 | + mMediaPlayer.setOnPreparedListener(mPreparedListener); | ||
223 | + mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); | ||
224 | + mMediaPlayer.setOnCompletionListener(mCompletionListener); | ||
225 | + mMediaPlayer.setOnErrorListener(mErrorListener); | ||
226 | + mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); | ||
227 | + mMediaPlayer.setOnInfoListener(mInfoListener); | ||
228 | + mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener); | ||
229 | + mMediaPlayer.setOnSubtitleUpdateListener(mSubtitleUpdateListener); | ||
230 | + mMediaPlayer.setDataSource(mContext, mUri); | ||
231 | + mMediaPlayer.setDisplay(mSurfaceHolder); | ||
232 | + mMediaPlayer.setScreenOnWhilePlaying(true); | ||
233 | + mMediaPlayer.prepareAsync(); | ||
234 | + mCurrentState = STATE_PREPARING; | ||
235 | + attachMediaController(); | ||
236 | + } catch (IOException ex) { | ||
237 | + Log.e("Unable to open content: " + mUri, ex); | ||
238 | + mCurrentState = STATE_ERROR; | ||
239 | + mTargetState = STATE_ERROR; | ||
240 | + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); | ||
241 | + return; | ||
242 | + } catch (IllegalArgumentException ex) { | ||
243 | + Log.e("Unable to open content: " + mUri, ex); | ||
244 | + mCurrentState = STATE_ERROR; | ||
245 | + mTargetState = STATE_ERROR; | ||
246 | + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); | ||
247 | + return; | ||
248 | + } | ||
249 | + } | ||
250 | + | ||
251 | + public void setMediaController(MediaController controller) { | ||
252 | + if (mMediaController != null) | ||
253 | + mMediaController.hide(); | ||
254 | + mMediaController = controller; | ||
255 | + attachMediaController(); | ||
256 | + } | ||
257 | + | ||
258 | + private void attachMediaController() { | ||
259 | + if (mMediaPlayer != null && mMediaController != null) { | ||
260 | + mMediaController.setMediaPlayer(this); | ||
261 | + View anchorView = this.getParent() instanceof View ? (View) this.getParent() : this; | ||
262 | + mMediaController.setAnchorView(anchorView); | ||
263 | + mMediaController.setEnabled(isInPlaybackState()); | ||
264 | + | ||
265 | + if (mUri != null) { | ||
266 | + List<String> paths = mUri.getPathSegments(); | ||
267 | + String name = paths == null || paths.isEmpty() ? "null" : paths.get(paths.size() - 1); | ||
268 | + mMediaController.setFileName(name); | ||
269 | + } | ||
270 | + } | ||
271 | + } | ||
272 | + | ||
273 | + OnVideoSizeChangedListener mSizeChangedListener = new OnVideoSizeChangedListener() { | ||
274 | + public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { | ||
275 | + Log.d("onVideoSizeChanged: (%dx%d)", width, height); | ||
276 | + mVideoWidth = mp.getVideoWidth(); | ||
277 | + mVideoHeight = mp.getVideoHeight(); | ||
278 | + mVideoAspectRatio = mp.getVideoAspectRatio(); | ||
279 | + if (mVideoWidth != 0 && mVideoHeight != 0) | ||
280 | + setVideoLayout(mVideoLayout, mAspectRatio); | ||
281 | + } | ||
282 | + }; | ||
283 | + | ||
284 | + OnPreparedListener mPreparedListener = new OnPreparedListener() { | ||
285 | + public void onPrepared(MediaPlayer mp) { | ||
286 | + Log.d("onPrepared"); | ||
287 | + mCurrentState = STATE_PREPARED; | ||
288 | + mTargetState = STATE_PLAYING; | ||
289 | + | ||
290 | + if (mOnPreparedListener != null) | ||
291 | + mOnPreparedListener.onPrepared(mMediaPlayer); | ||
292 | + if (mMediaController != null) | ||
293 | + mMediaController.setEnabled(true); | ||
294 | + mVideoWidth = mp.getVideoWidth(); | ||
295 | + mVideoHeight = mp.getVideoHeight(); | ||
296 | + mVideoAspectRatio = mp.getVideoAspectRatio(); | ||
297 | + | ||
298 | + long seekToPosition = mSeekWhenPrepared; | ||
299 | + | ||
300 | + if (seekToPosition != 0) | ||
301 | + seekTo(seekToPosition); | ||
302 | + if (mVideoWidth != 0 && mVideoHeight != 0) { | ||
303 | + setVideoLayout(mVideoLayout, mAspectRatio); | ||
304 | + if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) { | ||
305 | + if (mTargetState == STATE_PLAYING) { | ||
306 | + start(); | ||
307 | + if (mMediaController != null) | ||
308 | + mMediaController.show(); | ||
309 | + } else if (!isPlaying() && (seekToPosition != 0 || getCurrentPosition() > 0)) { | ||
310 | + if (mMediaController != null) | ||
311 | + mMediaController.show(0); | ||
312 | + } | ||
313 | + } | ||
314 | + } else if (mTargetState == STATE_PLAYING) { | ||
315 | + start(); | ||
316 | + } | ||
317 | + } | ||
318 | + }; | ||
319 | + | ||
320 | + private OnCompletionListener mCompletionListener = new OnCompletionListener() { | ||
321 | + public void onCompletion(MediaPlayer mp) { | ||
322 | + Log.d("onCompletion"); | ||
323 | + mCurrentState = STATE_PLAYBACK_COMPLETED; | ||
324 | + mTargetState = STATE_PLAYBACK_COMPLETED; | ||
325 | + if (mMediaController != null) | ||
326 | + mMediaController.hide(); | ||
327 | + if (mOnCompletionListener != null) | ||
328 | + mOnCompletionListener.onCompletion(mMediaPlayer); | ||
329 | + } | ||
330 | + }; | ||
331 | + | ||
332 | + private OnErrorListener mErrorListener = new OnErrorListener() { | ||
333 | + public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { | ||
334 | + Log.d("Error: %d, %d", framework_err, impl_err); | ||
335 | + mCurrentState = STATE_ERROR; | ||
336 | + mTargetState = STATE_ERROR; | ||
337 | + if (mMediaController != null) | ||
338 | + mMediaController.hide(); | ||
339 | + | ||
340 | + if (mOnErrorListener != null) { | ||
341 | + if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) | ||
342 | + return true; | ||
343 | + } | ||
344 | + | ||
345 | + if (getWindowToken() != null) { | ||
346 | + int message = framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK ? R.string.vitamio_videoview_error_text_invalid_progressive_playback : R.string.vitamio_videoview_error_text_unknown; | ||
347 | + | ||
348 | + new AlertDialog.Builder(mContext).setTitle(R.string.vitamio_videoview_error_title).setMessage(message).setPositiveButton(R.string.vitamio_videoview_error_button, new DialogInterface.OnClickListener() { | ||
349 | + public void onClick(DialogInterface dialog, int whichButton) { | ||
350 | + if (mOnCompletionListener != null) | ||
351 | + mOnCompletionListener.onCompletion(mMediaPlayer); | ||
352 | + } | ||
353 | + }).setCancelable(false).show(); | ||
354 | + } | ||
355 | + return true; | ||
356 | + } | ||
357 | + }; | ||
358 | + | ||
359 | + private OnBufferingUpdateListener mBufferingUpdateListener = new OnBufferingUpdateListener() { | ||
360 | + public void onBufferingUpdate(MediaPlayer mp, int percent) { | ||
361 | + mCurrentBufferPercentage = percent; | ||
362 | + if (mOnBufferingUpdateListener != null) | ||
363 | + mOnBufferingUpdateListener.onBufferingUpdate(mp, percent); | ||
364 | + } | ||
365 | + }; | ||
366 | + | ||
367 | + private OnInfoListener mInfoListener = new OnInfoListener() { | ||
368 | + @Override | ||
369 | + public boolean onInfo(MediaPlayer mp, int what, int extra) { | ||
370 | + Log.d("onInfo: (%d, %d)", what, extra); | ||
371 | + if (mOnInfoListener != null) { | ||
372 | + mOnInfoListener.onInfo(mp, what, extra); | ||
373 | + } else if (mMediaPlayer != null) { | ||
374 | + if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) | ||
375 | + mMediaPlayer.pause(); | ||
376 | + else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) | ||
377 | + mMediaPlayer.start(); | ||
378 | + } | ||
379 | + | ||
380 | + return true; | ||
381 | + } | ||
382 | + }; | ||
383 | + | ||
384 | + private OnSeekCompleteListener mSeekCompleteListener = new OnSeekCompleteListener() { | ||
385 | + @Override | ||
386 | + public void onSeekComplete(MediaPlayer mp) { | ||
387 | + Log.d("onSeekComplete"); | ||
388 | + if (mOnSeekCompleteListener != null) | ||
389 | + mOnSeekCompleteListener.onSeekComplete(mp); | ||
390 | + } | ||
391 | + }; | ||
392 | + | ||
393 | + private OnSubtitleUpdateListener mSubtitleUpdateListener = new OnSubtitleUpdateListener() { | ||
394 | + @Override | ||
395 | + public void onSubtitleUpdate(byte[] pixels, int width, int height) { | ||
396 | + Log.i("onSubtitleUpdate: bitmap subtitle, %dx%d", width, height); | ||
397 | + if (mOnSubtitleUpdateListener != null) | ||
398 | + mOnSubtitleUpdateListener.onSubtitleUpdate(pixels, width, height); | ||
399 | + } | ||
400 | + | ||
401 | + @Override | ||
402 | + public void onSubtitleUpdate(String text) { | ||
403 | + Log.i("onSubtitleUpdate: %s", text); | ||
404 | + if (mOnSubtitleUpdateListener != null) | ||
405 | + mOnSubtitleUpdateListener.onSubtitleUpdate(text); | ||
406 | + } | ||
407 | + }; | ||
408 | + | ||
409 | + public void setOnPreparedListener(OnPreparedListener l) { | ||
410 | + mOnPreparedListener = l; | ||
411 | + } | ||
412 | + | ||
413 | + public void setOnCompletionListener(OnCompletionListener l) { | ||
414 | + mOnCompletionListener = l; | ||
415 | + } | ||
416 | + | ||
417 | + public void setOnErrorListener(OnErrorListener l) { | ||
418 | + mOnErrorListener = l; | ||
419 | + } | ||
420 | + | ||
421 | + public void setOnBufferingUpdateListener(OnBufferingUpdateListener l) { | ||
422 | + mOnBufferingUpdateListener = l; | ||
423 | + } | ||
424 | + | ||
425 | + public void setOnSeekCompleteListener(OnSeekCompleteListener l) { | ||
426 | + mOnSeekCompleteListener = l; | ||
427 | + } | ||
428 | + | ||
429 | + public void setOnSubtitleUpdateListener(OnSubtitleUpdateListener l) { | ||
430 | + mOnSubtitleUpdateListener = l; | ||
431 | + } | ||
432 | + | ||
433 | + public void setOnInfoListener(OnInfoListener l) { | ||
434 | + mOnInfoListener = l; | ||
435 | + } | ||
436 | + | ||
437 | + SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() { | ||
438 | + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { | ||
439 | + mSurfaceWidth = w; | ||
440 | + mSurfaceHeight = h; | ||
441 | + boolean isValidState = (mTargetState == STATE_PLAYING); | ||
442 | + boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h); | ||
443 | + if (mMediaPlayer != null && isValidState && hasValidSize) { | ||
444 | + if (mSeekWhenPrepared != 0) | ||
445 | + seekTo(mSeekWhenPrepared); | ||
446 | + start(); | ||
447 | + if (mMediaController != null) { | ||
448 | + if (mMediaController.isShowing()) | ||
449 | + mMediaController.hide(); | ||
450 | + mMediaController.show(); | ||
451 | + } | ||
452 | + } | ||
453 | + } | ||
454 | + | ||
455 | + public void surfaceCreated(SurfaceHolder holder) { | ||
456 | + mSurfaceHolder = holder; | ||
457 | + if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND && mTargetState == STATE_RESUME) { | ||
458 | + mMediaPlayer.setDisplay(mSurfaceHolder); | ||
459 | + resume(); | ||
460 | + } else { | ||
461 | + openVideo(); | ||
462 | + } | ||
463 | + } | ||
464 | + | ||
465 | + public void surfaceDestroyed(SurfaceHolder holder) { | ||
466 | + mSurfaceHolder = null; | ||
467 | + if (mMediaController != null) | ||
468 | + mMediaController.hide(); | ||
469 | + if (mCurrentState != STATE_SUSPEND) | ||
470 | + release(true); | ||
471 | + } | ||
472 | + }; | ||
473 | + | ||
474 | + private void release(boolean cleartargetstate) { | ||
475 | + if (mMediaPlayer != null) { | ||
476 | + mMediaPlayer.reset(); | ||
477 | + mMediaPlayer.release(); | ||
478 | + mMediaPlayer = null; | ||
479 | + mCurrentState = STATE_IDLE; | ||
480 | + if (cleartargetstate) | ||
481 | + mTargetState = STATE_IDLE; | ||
482 | + } | ||
483 | + } | ||
484 | + | ||
485 | + @Override | ||
486 | + public boolean onTouchEvent(MotionEvent ev) { | ||
487 | + if (isInPlaybackState() && mMediaController != null) | ||
488 | + toggleMediaControlsVisiblity(); | ||
489 | + return false; | ||
490 | + } | ||
491 | + | ||
492 | + @Override | ||
493 | + public boolean onTrackballEvent(MotionEvent ev) { | ||
494 | + if (isInPlaybackState() && mMediaController != null) | ||
495 | + toggleMediaControlsVisiblity(); | ||
496 | + return false; | ||
497 | + } | ||
498 | + | ||
499 | + @Override | ||
500 | + public boolean onKeyDown(int keyCode, KeyEvent event) { | ||
501 | + boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_MENU && keyCode != KeyEvent.KEYCODE_CALL && keyCode != KeyEvent.KEYCODE_ENDCALL; | ||
502 | + if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { | ||
503 | + if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE) { | ||
504 | + if (mMediaPlayer.isPlaying()) { | ||
505 | + pause(); | ||
506 | + mMediaController.show(); | ||
507 | + } else { | ||
508 | + start(); | ||
509 | + mMediaController.hide(); | ||
510 | + } | ||
511 | + return true; | ||
512 | + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP && mMediaPlayer.isPlaying()) { | ||
513 | + pause(); | ||
514 | + mMediaController.show(); | ||
515 | + } else { | ||
516 | + toggleMediaControlsVisiblity(); | ||
517 | + } | ||
518 | + } | ||
519 | + | ||
520 | + return super.onKeyDown(keyCode, event); | ||
521 | + } | ||
522 | + | ||
523 | + private void toggleMediaControlsVisiblity() { | ||
524 | + if (mMediaController.isShowing()) { | ||
525 | + mMediaController.hide(); | ||
526 | + } else { | ||
527 | + mMediaController.show(); | ||
528 | + } | ||
529 | + } | ||
530 | + | ||
531 | + public void start() { | ||
532 | + if (isInPlaybackState()) { | ||
533 | + mMediaPlayer.start(); | ||
534 | + mCurrentState = STATE_PLAYING; | ||
535 | + } | ||
536 | + mTargetState = STATE_PLAYING; | ||
537 | + } | ||
538 | + | ||
539 | + public void pause() { | ||
540 | + if (isInPlaybackState()) { | ||
541 | + if (mMediaPlayer.isPlaying()) { | ||
542 | + mMediaPlayer.pause(); | ||
543 | + mCurrentState = STATE_PAUSED; | ||
544 | + } | ||
545 | + } | ||
546 | + mTargetState = STATE_PAUSED; | ||
547 | + } | ||
548 | + | ||
549 | + public void suspend() { | ||
550 | + if (isInPlaybackState()) { | ||
551 | + release(false); | ||
552 | + mCurrentState = STATE_SUSPEND_UNSUPPORTED; | ||
553 | + Log.d("Unable to suspend video. Release MediaPlayer."); | ||
554 | + } | ||
555 | + } | ||
556 | + | ||
557 | + public void resume() { | ||
558 | + if (mSurfaceHolder == null && mCurrentState == STATE_SUSPEND) { | ||
559 | + mTargetState = STATE_RESUME; | ||
560 | + } else if (mCurrentState == STATE_SUSPEND_UNSUPPORTED) { | ||
561 | + openVideo(); | ||
562 | + } | ||
563 | + } | ||
564 | + | ||
565 | + public long getDuration() { | ||
566 | + if (isInPlaybackState()) { | ||
567 | + if (mDuration > 0) | ||
568 | + return mDuration; | ||
569 | + mDuration = mMediaPlayer.getDuration(); | ||
570 | + return mDuration; | ||
571 | + } | ||
572 | + mDuration = -1; | ||
573 | + return mDuration; | ||
574 | + } | ||
575 | + | ||
576 | + public long getCurrentPosition() { | ||
577 | + if (isInPlaybackState()) | ||
578 | + return mMediaPlayer.getCurrentPosition(); | ||
579 | + return 0; | ||
580 | + } | ||
581 | + | ||
582 | + public void seekTo(long msec) { | ||
583 | + if (isInPlaybackState()) { | ||
584 | + mMediaPlayer.seekTo(msec); | ||
585 | + mSeekWhenPrepared = 0; | ||
586 | + } else { | ||
587 | + mSeekWhenPrepared = msec; | ||
588 | + } | ||
589 | + } | ||
590 | + | ||
591 | + public boolean isPlaying() { | ||
592 | + return isInPlaybackState() && mMediaPlayer.isPlaying(); | ||
593 | + } | ||
594 | + | ||
595 | + public int getBufferPercentage() { | ||
596 | + if (mMediaPlayer != null) | ||
597 | + return mCurrentBufferPercentage; | ||
598 | + return 0; | ||
599 | + } | ||
600 | + | ||
601 | + public void setVolume(float leftVolume, float rightVolume) { | ||
602 | + if (mMediaPlayer != null) | ||
603 | + mMediaPlayer.setVolume(leftVolume, rightVolume); | ||
604 | + } | ||
605 | + | ||
606 | + public int getVideoWidth() { | ||
607 | + return mVideoWidth; | ||
608 | + } | ||
609 | + | ||
610 | + public int getVideoHeight() { | ||
611 | + return mVideoHeight; | ||
612 | + } | ||
613 | + | ||
614 | + public float getVideoAspectRatio() { | ||
615 | + return mVideoAspectRatio; | ||
616 | + } | ||
617 | + | ||
618 | + public void setVideoQuality(int quality) { | ||
619 | + if (mMediaPlayer != null) | ||
620 | + mMediaPlayer.setVideoQuality(quality); | ||
621 | + } | ||
622 | + | ||
623 | + public void setBufferSize(int bufSize) { | ||
624 | + if (mMediaPlayer != null) | ||
625 | + mMediaPlayer.setBufferSize(bufSize); | ||
626 | + } | ||
627 | + | ||
628 | + public boolean isBuffering() { | ||
629 | + if (mMediaPlayer != null) | ||
630 | + return mMediaPlayer.isBuffering(); | ||
631 | + return false; | ||
632 | + } | ||
633 | + | ||
634 | + public void setMetaEncoding(String encoding) { | ||
635 | + if (mMediaPlayer != null) | ||
636 | + mMediaPlayer.setMetaEncoding(encoding); | ||
637 | + } | ||
638 | + | ||
639 | + public String getMetaEncoding() { | ||
640 | + if (mMediaPlayer != null) | ||
641 | + return mMediaPlayer.getMetaEncoding(); | ||
642 | + return null; | ||
643 | + } | ||
644 | + | ||
645 | + public HashMap<String, Integer> getAudioTrackMap(String encoding) { | ||
646 | + if (mMediaPlayer != null) | ||
647 | + return mMediaPlayer.getAudioTrackMap(encoding); | ||
648 | + return null; | ||
649 | + } | ||
650 | + | ||
651 | + public int getAudioTrack() { | ||
652 | + if (mMediaPlayer != null) | ||
653 | + return mMediaPlayer.getAudioTrack(); | ||
654 | + return -1; | ||
655 | + } | ||
656 | + | ||
657 | + public void setAudioTrack(int audioIndex) { | ||
658 | + if (mMediaPlayer != null) | ||
659 | + mMediaPlayer.setAudioTrack(audioIndex); | ||
660 | + } | ||
661 | + | ||
662 | + public void setSubShown(boolean shown) { | ||
663 | + if (mMediaPlayer != null) | ||
664 | + mMediaPlayer.setSubShown(shown); | ||
665 | + } | ||
666 | + | ||
667 | + public void setSubEncoding(String encoding) { | ||
668 | + if (mMediaPlayer != null) | ||
669 | + mMediaPlayer.setSubEncoding(encoding); | ||
670 | + } | ||
671 | + | ||
672 | + public int getSubLocation() { | ||
673 | + if (mMediaPlayer != null) | ||
674 | + return mMediaPlayer.getSubLocation(); | ||
675 | + return -1; | ||
676 | + } | ||
677 | + | ||
678 | + public void setSubPath(String subPath) { | ||
679 | + if (mMediaPlayer != null) | ||
680 | + mMediaPlayer.setSubPath(subPath); | ||
681 | + } | ||
682 | + | ||
683 | + public String getSubPath() { | ||
684 | + if (mMediaPlayer != null) | ||
685 | + return mMediaPlayer.getSubPath(); | ||
686 | + return null; | ||
687 | + } | ||
688 | + | ||
689 | + public void setSubTrack(int trackId) { | ||
690 | + if (mMediaPlayer != null) | ||
691 | + mMediaPlayer.setSubTrack(trackId); | ||
692 | + } | ||
693 | + | ||
694 | + public int getSubTrack() { | ||
695 | + if (mMediaPlayer != null) | ||
696 | + return mMediaPlayer.getSubTrack(); | ||
697 | + return -1; | ||
698 | + } | ||
699 | + | ||
700 | + public HashMap<String, Integer> getSubTrackMap(String encoding) { | ||
701 | + if (mMediaPlayer != null) | ||
702 | + return mMediaPlayer.getSubTrackMap(encoding); | ||
703 | + return null; | ||
704 | + } | ||
705 | + | ||
706 | + protected boolean isInPlaybackState() { | ||
707 | + return (mMediaPlayer != null && mCurrentState != STATE_ERROR && mCurrentState != STATE_IDLE && mCurrentState != STATE_PREPARING); | ||
708 | + } | ||
709 | + | ||
710 | + public boolean canPause() { | ||
711 | + return mCanPause; | ||
712 | + } | ||
713 | + | ||
714 | + public boolean canSeekBackward() { | ||
715 | + return mCanSeekBack; | ||
716 | + } | ||
717 | + | ||
718 | + public boolean canSeekForward() { | ||
719 | + return mCanSeekForward; | ||
720 | + } | ||
721 | +} |
project.properties
res/layout/activity_video.xml
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | android:layout_width="match_parent" | 3 | android:layout_width="match_parent" |
4 | android:layout_height="match_parent" > | 4 | android:layout_height="match_parent" > |
5 | 5 | ||
6 | - <VideoView | 6 | + <io.vov.vitamio.widget.VideoView |
7 | android:id="@+id/videoView1" | 7 | android:id="@+id/videoView1" |
8 | android:layout_width="wrap_content" | 8 | android:layout_width="wrap_content" |
9 | android:layout_height="wrap_content" | 9 | android:layout_height="wrap_content" |
src/com/upc/pbe/upcnews/VideoActivity.java
@@ -2,15 +2,15 @@ package com.upc.pbe.upcnews; | @@ -2,15 +2,15 @@ package com.upc.pbe.upcnews; | ||
2 | 2 | ||
3 | import java.io.IOException; | 3 | import java.io.IOException; |
4 | 4 | ||
5 | +import io.vov.vitamio.widget.VideoView; | ||
5 | import android.app.Activity; | 6 | import android.app.Activity; |
6 | -import android.media.MediaPlayer; | 7 | +import io.vov.vitamio.MediaPlayer; |
7 | import android.net.Uri; | 8 | import android.net.Uri; |
8 | import android.os.Bundle; | 9 | import android.os.Bundle; |
9 | import android.util.Log; | 10 | import android.util.Log; |
10 | import android.view.Menu; | 11 | import android.view.Menu; |
11 | -import android.widget.MediaController; | 12 | +import io.vov.vitamio.widget.MediaController; |
12 | import android.widget.Toast; | 13 | import android.widget.Toast; |
13 | -import android.widget.VideoView; | ||
14 | 14 | ||
15 | //Tercera activitat principal, executa la reproduccio del video sencer | 15 | //Tercera activitat principal, executa la reproduccio del video sencer |
16 | public class VideoActivity extends Activity { | 16 | public class VideoActivity extends Activity { |