提交 135b5fec 编写于 作者: Z Zhang Rui

ijkmediawidget: introduce VideoView, MediaController

上级 c62b7ca1
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tv.danmaku.ijk.media.lib"
android:versionCode="1"
android:versionName="1.0" >
android:versionName="0.0.1" >
<uses-sdk
android:minSdkVersion="9"
......
/*
* Copyright (C) 2006 The Android Open Source Project
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Based on android.media.MediaPlayer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.player;
import java.io.IOException;
......
/*
* Copyright (C) 2006 The Android Open Source Project
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Based on android.media.MediaPlayer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.player;
import java.io.IOException;
......
/*
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.player;
import java.util.Locale;
import android.util.Log;
public class DebugLog {
public static boolean ENABLE_ERROR = false;
public static boolean ENABLE_INFO = false;
public static boolean ENABLE_WARN = false;
public static boolean ENABLE_DEBUG = false;
public static boolean ENABLE_VERBOSE = false;
public static void setDebug(boolean debug) {
ENABLE_ERROR = debug;
ENABLE_INFO = debug;
ENABLE_WARN = debug;
ENABLE_DEBUG = debug;
ENABLE_VERBOSE = debug;
}
public static int e(String tag, String msg) {
if (Pragma.ENABLE_ERROR) {
if (ENABLE_ERROR) {
return Log.e(tag, msg);
}
......@@ -13,7 +43,7 @@ public class DebugLog {
}
public static int e(String tag, String msg, Throwable tr) {
if (Pragma.ENABLE_ERROR) {
if (ENABLE_ERROR) {
return Log.e(tag, msg, tr);
}
......@@ -21,7 +51,7 @@ public class DebugLog {
}
public static int efmt(String tag, String fmt, Object... args) {
if (Pragma.ENABLE_ERROR) {
if (ENABLE_ERROR) {
String msg = String.format(Locale.US, fmt, args);
return Log.e(tag, msg);
}
......@@ -30,7 +60,7 @@ public class DebugLog {
}
public static int i(String tag, String msg) {
if (Pragma.ENABLE_INFO) {
if (ENABLE_INFO) {
return Log.i(tag, msg);
}
......@@ -38,7 +68,7 @@ public class DebugLog {
}
public static int i(String tag, String msg, Throwable tr) {
if (Pragma.ENABLE_INFO) {
if (ENABLE_INFO) {
return Log.i(tag, msg, tr);
}
......@@ -46,7 +76,7 @@ public class DebugLog {
}
public static int ifmt(String tag, String fmt, Object... args) {
if (Pragma.ENABLE_INFO) {
if (ENABLE_INFO) {
String msg = String.format(Locale.US, fmt, args);
return Log.i(tag, msg);
}
......@@ -55,7 +85,7 @@ public class DebugLog {
}
public static int w(String tag, String msg) {
if (Pragma.ENABLE_WARN) {
if (ENABLE_WARN) {
return Log.w(tag, msg);
}
......@@ -63,7 +93,7 @@ public class DebugLog {
}
public static int w(String tag, String msg, Throwable tr) {
if (Pragma.ENABLE_WARN) {
if (ENABLE_WARN) {
return Log.w(tag, msg, tr);
}
......@@ -71,7 +101,7 @@ public class DebugLog {
}
public static int wfmt(String tag, String fmt, Object... args) {
if (Pragma.ENABLE_WARN) {
if (ENABLE_WARN) {
String msg = String.format(Locale.US, fmt, args);
return Log.w(tag, msg);
}
......@@ -80,7 +110,7 @@ public class DebugLog {
}
public static int d(String tag, String msg) {
if (Pragma.ENABLE_DEBUG) {
if (ENABLE_DEBUG) {
return Log.d(tag, msg);
}
......@@ -88,7 +118,7 @@ public class DebugLog {
}
public static int d(String tag, String msg, Throwable tr) {
if (Pragma.ENABLE_DEBUG) {
if (ENABLE_DEBUG) {
return Log.d(tag, msg, tr);
}
......@@ -96,7 +126,7 @@ public class DebugLog {
}
public static int dfmt(String tag, String fmt, Object... args) {
if (Pragma.ENABLE_DEBUG) {
if (ENABLE_DEBUG) {
String msg = String.format(Locale.US, fmt, args);
return Log.d(tag, msg);
}
......@@ -105,7 +135,7 @@ public class DebugLog {
}
public static int v(String tag, String msg) {
if (Pragma.ENABLE_VERBOSE) {
if (ENABLE_VERBOSE) {
return Log.v(tag, msg);
}
......@@ -113,7 +143,7 @@ public class DebugLog {
}
public static int v(String tag, String msg, Throwable tr) {
if (Pragma.ENABLE_VERBOSE) {
if (ENABLE_VERBOSE) {
return Log.v(tag, msg, tr);
}
......@@ -121,7 +151,7 @@ public class DebugLog {
}
public static int vfmt(String tag, String fmt, Object... args) {
if (Pragma.ENABLE_VERBOSE) {
if (ENABLE_VERBOSE) {
String msg = String.format(Locale.US, fmt, args);
return Log.v(tag, msg);
}
......@@ -130,13 +160,13 @@ public class DebugLog {
}
public static void printStackTrace(Throwable e) {
if (Pragma.ENABLE_WARN) {
if (ENABLE_WARN) {
e.printStackTrace();
}
}
public static void printCause(Throwable e) {
if (Pragma.ENABLE_WARN) {
if (ENABLE_WARN) {
Throwable cause = e.getCause();
if (cause != null)
e = cause;
......
/*
* Copyright (C) 2006 The Android Open Source Project
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Based on android.media.MediaPlayer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.player;
import java.io.FileDescriptor;
......
/*
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.player;
/*-
* Config fields at startup
* configurated by app project
*/
public class Pragma {
public static boolean ENABLE_ERROR = false;
public static boolean ENABLE_INFO = false;
public static boolean ENABLE_WARN = false;
public static boolean ENABLE_DEBUG = false;
public static boolean ENABLE_VERBOSE = false;
public static void setDebug(boolean debug) {
DebugLog.setDebug(debug);
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tv.danmaku.ijk.media.widget"
android:versionCode="1"
android:versionName="0.0.1" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="17" />
</manifest>
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-17
android.library=true
android.library.reference.1=../ijkmediaplayer
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/mediacontroller_pause02" android:state_focused="true" android:state_pressed="false"/>
<item android:drawable="@drawable/mediacontroller_pause02" android:state_focused="true" android:state_pressed="true"/>
<item android:drawable="@drawable/mediacontroller_pause02" android:state_focused="false" android:state_pressed="true"/>
<item android:drawable="@drawable/mediacontroller_pause01"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/mediacontroller_play02" android:state_focused="true" android:state_pressed="false"/>
<item android:drawable="@drawable/mediacontroller_play02" android:state_focused="true" android:state_pressed="true"/>
<item android:drawable="@drawable/mediacontroller_play02" android:state_focused="false" android:state_pressed="true"/>
<item android:drawable="@drawable/mediacontroller_play01"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 The Android Open Source Project Licensed under the
Apache License, Version 2.0 (the "License"); you may not use this file except
in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
OR CONDITIONS OF ANY KIND, either express or implied. See the License for
the specific language governing permissions and limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/scrubber_control_disabled_holo" android:state_enabled="false"/>
<item android:drawable="@drawable/scrubber_control_pressed_holo" android:state_pressed="true"/>
<item android:drawable="@drawable/scrubber_control_focused_holo" android:state_selected="true"/>
<item android:drawable="@drawable/scrubber_control_normal_holo"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 The Android Open Source Project Licensed under the
Apache License, Version 2.0 (the "License"); you may not use this file except
in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
OR CONDITIONS OF ANY KIND, either express or implied. See the License for
the specific language governing permissions and limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@android:id/background"
android:drawable="@drawable/scrubber_track_holo_dark"/>
<item android:id="@android:id/secondaryProgress">
<scale
android:drawable="@drawable/scrubber_secondary_holo"
android:scaleWidth="100%" />
</item>
<item android:id="@android:id/progress">
<scale
android:drawable="@drawable/scrubber_primary_holo"
android:scaleWidth="100%" />
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="74dip"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0.0dip"
android:layout_marginLeft="0.0dip"
android:layout_marginRight="0.0dip"
android:background="@drawable/mediacontroller_bg"
android:orientation="horizontal" >
<ImageButton
android:id="@+id/mediacontroller_play_pause"
android:layout_width="54.6dip"
android:layout_height="32dip"
android:layout_alignParentRight="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_marginRight="7.0dip"
android:background="#00000000"
android:contentDescription="@string/mediacontroller_play_pause"
android:gravity="center"
android:src="@drawable/mediacontroller_pause_button" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dip"
android:layout_marginLeft="7.0dip"
android:layout_marginRight="7.0dip"
android:layout_marginTop="2dip"
android:layout_toLeftOf="@+id/mediacontroller_play_pause" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/mediacontroller_time_current"
style="@style/MediaController_Text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
<TextView
android:id="@+id/mediacontroller_time_total"
style="@style/MediaController_Text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
<SeekBar
android:id="@+id/mediacontroller_seekbar"
style="@style/MediaController_SeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:focusable="true"
android:max="1000" />
<TextView
android:id="@+id/mediacontroller_file_name"
style="@style/MediaController_Text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:ellipsize="marquee"
android:singleLine="true" />
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
<resources>
<!--
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>
<resources>
<!--
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="vitamio_name">Vitamio</string>
<string name="vitamio_init_decoders">Initializing decoders…</string>
<string name="vitamio_videoview_error_title">Cannot play video</string>
<string name="vitamio_videoview_error_text_invalid_progressive_playback">Sorry, this video is not valid for streaming to
this device.</string>
<string name="vitamio_videoview_error_text_unknown">Sorry, this video cannot be played.</string>
<string name="vitamio_videoview_error_button">OK</string>
<string name="mediacontroller_play_pause">Play/Pause</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<style name="MediaController_SeekBar" parent="android:Widget.SeekBar">
<item name="android:progressDrawable">@drawable/scrubber_progress_horizontal_holo_dark</item>
<item name="android:indeterminateDrawable">@drawable/scrubber_progress_horizontal_holo_dark</item>
<item name="android:minHeight">13dip</item>
<item name="android:maxHeight">13dip</item>
<item name="android:thumb">@drawable/scrubber_control_selector_holo</item>
<item name="android:thumbOffset">16dip</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
</style>
<style name="MediaController_Text">
<item name="android:textColor">#ffffffff</item>
<item name="android:textSize">14sp</item>
<item name="android:textStyle">bold</item>
</style>
</resources>
\ No newline at end of file
/*
* Copyright (C) 2012 YIXIA.COM
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Based on https://github.com/yixia/VitamioBundle
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews.RemoteView;
@RemoteView
public class CenterLayout extends ViewGroup {
private int mPaddingLeft = 0;
private int mPaddingRight = 0;
private int mPaddingTop = 0;
private int mPaddingBottom = 0;
private int mWidth, mHeight;
public CenterLayout(Context context) {
super(context);
}
public CenterLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CenterLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
measureChildren(widthMeasureSpec, heightMeasureSpec);
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
int childRight;
int childBottom;
CenterLayout.LayoutParams lp = (CenterLayout.LayoutParams) child.getLayoutParams();
childRight = lp.x + child.getMeasuredWidth();
childBottom = lp.y + child.getMeasuredHeight();
maxWidth = Math.max(maxWidth, childRight);
maxHeight = Math.max(maxHeight, childBottom);
}
}
maxWidth += mPaddingLeft + mPaddingRight;
maxHeight += mPaddingTop + mPaddingBottom;
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
CenterLayout.LayoutParams lp = (CenterLayout.LayoutParams) child.getLayoutParams();
int childLeft = mPaddingLeft + lp.x;
if (lp.width > 0)
childLeft += (int) ((mWidth - lp.width) / 2.0);
else
childLeft += (int) ((mWidth - child.getMeasuredWidth()) / 2.0);
int childTop = mPaddingTop + lp.y;
if (lp.height > 0)
childTop += (int) ((mHeight - lp.height) / 2.0);
else
childTop += (int) ((mHeight - child.getMeasuredHeight()) / 2.0);
child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight());
}
}
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof CenterLayout.LayoutParams;
}
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
public static class LayoutParams extends ViewGroup.LayoutParams {
public int x;
public int y;
public LayoutParams(int width, int height, int x, int y) {
super(width, height);
this.x = x;
this.y = y;
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
}
}
/*
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.widget;
import java.util.Locale;
import android.util.Log;
public class DebugLog {
public static boolean ENABLE_ERROR = false;
public static boolean ENABLE_INFO = false;
public static boolean ENABLE_WARN = false;
public static boolean ENABLE_DEBUG = false;
public static boolean ENABLE_VERBOSE = false;
public static void setDebug(boolean debug) {
ENABLE_ERROR = debug;
ENABLE_INFO = debug;
ENABLE_WARN = debug;
ENABLE_DEBUG = debug;
ENABLE_VERBOSE = debug;
}
public static int e(String tag, String msg) {
if (ENABLE_ERROR) {
return Log.e(tag, msg);
}
return 0;
}
public static int e(String tag, String msg, Throwable tr) {
if (ENABLE_ERROR) {
return Log.e(tag, msg, tr);
}
return 0;
}
public static int efmt(String tag, String fmt, Object... args) {
if (ENABLE_ERROR) {
String msg = String.format(Locale.US, fmt, args);
return Log.e(tag, msg);
}
return 0;
}
public static int i(String tag, String msg) {
if (ENABLE_INFO) {
return Log.i(tag, msg);
}
return 0;
}
public static int i(String tag, String msg, Throwable tr) {
if (ENABLE_INFO) {
return Log.i(tag, msg, tr);
}
return 0;
}
public static int ifmt(String tag, String fmt, Object... args) {
if (ENABLE_INFO) {
String msg = String.format(Locale.US, fmt, args);
return Log.i(tag, msg);
}
return 0;
}
public static int w(String tag, String msg) {
if (ENABLE_WARN) {
return Log.w(tag, msg);
}
return 0;
}
public static int w(String tag, String msg, Throwable tr) {
if (ENABLE_WARN) {
return Log.w(tag, msg, tr);
}
return 0;
}
public static int wfmt(String tag, String fmt, Object... args) {
if (ENABLE_WARN) {
String msg = String.format(Locale.US, fmt, args);
return Log.w(tag, msg);
}
return 0;
}
public static int d(String tag, String msg) {
if (ENABLE_DEBUG) {
return Log.d(tag, msg);
}
return 0;
}
public static int d(String tag, String msg, Throwable tr) {
if (ENABLE_DEBUG) {
return Log.d(tag, msg, tr);
}
return 0;
}
public static int dfmt(String tag, String fmt, Object... args) {
if (ENABLE_DEBUG) {
String msg = String.format(Locale.US, fmt, args);
return Log.d(tag, msg);
}
return 0;
}
public static int v(String tag, String msg) {
if (ENABLE_VERBOSE) {
return Log.v(tag, msg);
}
return 0;
}
public static int v(String tag, String msg, Throwable tr) {
if (ENABLE_VERBOSE) {
return Log.v(tag, msg, tr);
}
return 0;
}
public static int vfmt(String tag, String fmt, Object... args) {
if (ENABLE_VERBOSE) {
String msg = String.format(Locale.US, fmt, args);
return Log.v(tag, msg);
}
return 0;
}
public static void printStackTrace(Throwable e) {
if (ENABLE_WARN) {
e.printStackTrace();
}
}
public static void printCause(Throwable e) {
if (ENABLE_WARN) {
Throwable cause = e.getCause();
if (cause != null)
e = cause;
printStackTrace(e);
}
}
}
/*
* Copyright (C) 2006 The Android Open Source Project
* Copyright (C) 2012 YIXIA.COM
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Based on https://github.com/yixia/VitamioBundle
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.widget;
import java.util.Locale;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
/**
* A view containing controls for a MediaPlayer. Typically contains the buttons
* like "Play/Pause" and a progress slider. It takes care of synchronizing the
* controls with the state of the MediaPlayer.
* <p>
* The way to use this class is to a) instantiate it programatically or b)
* create it in your xml layout.
*
* a) The MediaController will create a default set of controls and put them in
* a window floating above your application. Specifically, the controls will
* float above the view specified with setAnchorView(). By default, the window
* will disappear if left idle for three seconds and reappear when the user
* touches the anchor view. To customize the MediaController's style, layout and
* controls you should extend MediaController and override the {#link
* {@link #makeControllerView()} method.
*
* b) The MediaController is a FrameLayout, you can put it in your layout xml
* and get it through {@link #findViewById(int)}.
*
* NOTES: In each way, if you want customize the MediaController, the SeekBar's
* id must be mediacontroller_progress, the Play/Pause's must be
* mediacontroller_pause, current time's must be mediacontroller_time_current,
* total time's must be mediacontroller_time_total, file name's must be
* mediacontroller_file_name. And your resources must have a pause_button
* drawable and a play_button drawable.
* <p>
* Functions like show() and hide() have no effect when MediaController is
* created in an xml layout.
*/
public class MediaController extends FrameLayout {
private static final String TAG = MediaController.class.getSimpleName();
private MediaPlayerControl mPlayer;
private Context mContext;
private PopupWindow mWindow;
private int mAnimStyle;
private View mAnchor;
private View mRoot;
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private TextView mFileName;
private OutlineTextView mInfoView;
private String mTitle;
private long mDuration;
private boolean mShowing;
private boolean mDragging;
private boolean mInstantSeeking = true;
private static final int sDefaultTimeout = 3000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private boolean mFromXml = false;
private ImageButton mPauseButton;
private AudioManager mAM;
public MediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = this;
mFromXml = true;
initController(context);
}
public MediaController(Context context) {
super(context);
if (!mFromXml && initController(context))
initFloatingWindow();
}
private boolean initController(Context context) {
mContext = context;
mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
return true;
}
@Override
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
}
private void initFloatingWindow() {
mWindow = new PopupWindow(mContext);
mWindow.setFocusable(false);
mWindow.setBackgroundDrawable(null);
mWindow.setOutsideTouchable(true);
mAnimStyle = android.R.style.Animation;
}
/**
* Set the view that acts as the anchor for the control view. This can for
* example be a VideoView, or your Activity's main view.
*
* @param view
* The view to which to anchor the controller when it is visible.
*/
public void setAnchorView(View view) {
mAnchor = view;
if (!mFromXml) {
removeAllViews();
mRoot = makeControllerView();
mWindow.setContentView(mRoot);
mWindow.setWidth(LayoutParams.MATCH_PARENT);
mWindow.setHeight(LayoutParams.WRAP_CONTENT);
}
initControllerView(mRoot);
}
/**
* Create the view that holds the widgets that control playback. Derived
* classes can override this to create their own.
*
* @return The controller view.
*/
protected View makeControllerView() {
return ((LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.mediacontroller, this);
}
private void initControllerView(View v) {
mPauseButton = (ImageButton) v
.findViewById(R.id.mediacontroller_play_pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_seekbar);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
seeker.setThumbOffset(1);
}
mProgress.setMax(1000);
}
mEndTime = (TextView) v.findViewById(R.id.mediacontroller_time_total);
mCurrentTime = (TextView) v
.findViewById(R.id.mediacontroller_time_current);
mFileName = (TextView) v.findViewById(R.id.mediacontroller_file_name);
if (mFileName != null)
mFileName.setText(mTitle);
}
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
/**
* Control the action when the seekbar dragged by user
*
* @param seekWhenDragging
* True the media will seek periodically
*/
public void setInstantSeeking(boolean seekWhenDragging) {
mInstantSeeking = seekWhenDragging;
}
public void show() {
show(sDefaultTimeout);
}
/**
* Set the content of the file_name TextView
*
* @param name
*/
public void setFileName(String name) {
mTitle = name;
if (mFileName != null)
mFileName.setText(mTitle);
}
/**
* Set the View to hold some information when interact with the
* MediaController
*
* @param v
*/
public void setInfoView(OutlineTextView v) {
mInfoView = v;
}
private void disableUnsupportedButtons() {
try {
if (mPauseButton != null && !mPlayer.canPause())
mPauseButton.setEnabled(false);
} catch (IncompatibleClassChangeError ex) {
}
}
/**
* <p>
* Change the animation style resource for this controller.
* </p>
*
* <p>
* If the controller is showing, calling this method will take effect only
* the next time the controller is shown.
* </p>
*
* @param animationStyle
* animation style to use when the controller appears and
* disappears. Set to -1 for the default animation, 0 for no
* animation, or a resource identifier for an explicit animation.
*
*/
public void setAnimationStyle(int animationStyle) {
mAnimStyle = animationStyle;
}
/**
* Show the controller on screen. It will go away automatically after
* 'timeout' milliseconds of inactivity.
*
* @param timeout
* The timeout in milliseconds. Use 0 to show the controller
* until hide() is called.
*/
public void show(int timeout) {
if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) {
if (mPauseButton != null)
mPauseButton.requestFocus();
disableUnsupportedButtons();
if (mFromXml) {
setVisibility(View.VISIBLE);
} else {
int[] location = new int[2];
mAnchor.getLocationOnScreen(location);
Rect anchorRect = new Rect(location[0], location[1],
location[0] + mAnchor.getWidth(), location[1]
+ mAnchor.getHeight());
mWindow.setAnimationStyle(mAnimStyle);
mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY,
anchorRect.left, anchorRect.bottom);
}
mShowing = true;
if (mShownListener != null)
mShownListener.onShown();
}
updatePausePlay();
mHandler.sendEmptyMessage(SHOW_PROGRESS);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT),
timeout);
}
}
public boolean isShowing() {
return mShowing;
}
public void hide() {
if (mAnchor == null)
return;
if (mShowing) {
try {
mHandler.removeMessages(SHOW_PROGRESS);
if (mFromXml)
setVisibility(View.GONE);
else
mWindow.dismiss();
} catch (IllegalArgumentException ex) {
DebugLog.d(TAG, "MediaController already removed");
}
mShowing = false;
if (mHiddenListener != null)
mHiddenListener.onHidden();
}
}
public interface OnShownListener {
public void onShown();
}
private OnShownListener mShownListener;
public void setOnShownListener(OnShownListener l) {
mShownListener = l;
}
public interface OnHiddenListener {
public void onHidden();
}
private OnHiddenListener mHiddenListener;
public void setOnHiddenListener(OnHiddenListener l) {
mHiddenListener = l;
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
long pos;
switch (msg.what) {
case FADE_OUT:
hide();
break;
case SHOW_PROGRESS:
pos = setProgress();
if (!mDragging && mShowing) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
updatePausePlay();
}
break;
}
}
};
private long setProgress() {
if (mPlayer == null || mDragging)
return 0;
long position = mPlayer.getCurrentPosition();
long duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
long pos = 1000L * position / duration;
mProgress.setProgress((int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
mDuration = duration;
if (mEndTime != null)
mEndTime.setText(generateTime(mDuration));
if (mCurrentTime != null)
mCurrentTime.setText(generateTime(position));
return position;
}
private static String generateTime(long position) {
long totalSeconds = position / 1000;
long seconds = totalSeconds % 60;
long minutes = (totalSeconds / 60) % 60;
long hours = totalSeconds / 3600;
if (hours > 0) {
return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes,
seconds).toString();
} else {
return String.format(Locale.US, "%02d:%02d", minutes, seconds)
.toString();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0
&& (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
if (mPauseButton != null)
mPauseButton.requestFocus();
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_BACK
|| keyCode == KeyEvent.KEYCODE_MENU) {
hide();
return true;
} else {
show(sDefaultTimeout);
}
return super.dispatchKeyEvent(event);
}
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
private void updatePausePlay() {
if (mRoot == null || mPauseButton == null)
return;
if (mPlayer.isPlaying())
mPauseButton
.setImageResource(R.drawable.mediacontroller_pause_button);
else
mPauseButton
.setImageResource(R.drawable.mediacontroller_play_button);
}
private void doPauseResume() {
if (mPlayer.isPlaying())
mPlayer.pause();
else
mPlayer.start();
updatePausePlay();
}
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
mDragging = true;
show(3600000);
mHandler.removeMessages(SHOW_PROGRESS);
if (mInstantSeeking)
mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
if (mInfoView != null) {
mInfoView.setText("");
mInfoView.setVisibility(View.VISIBLE);
}
}
public void onProgressChanged(SeekBar bar, int progress,
boolean fromuser) {
if (!fromuser)
return;
long newposition = (mDuration * progress) / 1000;
String time = generateTime(newposition);
if (mInstantSeeking)
mPlayer.seekTo(newposition);
if (mInfoView != null)
mInfoView.setText(time);
if (mCurrentTime != null)
mCurrentTime.setText(time);
}
public void onStopTrackingTouch(SeekBar bar) {
if (!mInstantSeeking)
mPlayer.seekTo((mDuration * bar.getProgress()) / 1000);
if (mInfoView != null) {
mInfoView.setText("");
mInfoView.setVisibility(View.GONE);
}
show(sDefaultTimeout);
mHandler.removeMessages(SHOW_PROGRESS);
mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
mDragging = false;
mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
}
};
@Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null)
mPauseButton.setEnabled(enabled);
if (mProgress != null)
mProgress.setEnabled(enabled);
disableUnsupportedButtons();
super.setEnabled(enabled);
}
public interface MediaPlayerControl {
void start();
void pause();
long getDuration();
long getCurrentPosition();
void seekTo(long pos);
boolean isPlaying();
int getBufferPercentage();
boolean canPause();
boolean canSeekBackward();
boolean canSeekForward();
}
}
/*
* Copyright (C) 2011 Cedric Fung (wolfplanet@gmail.com)
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Based on https://github.com/yixia/VitamioBundle
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* Display text with border, use the same XML attrs as
* {@link android.widget.TextView}, except that {@link OutlineTextView} will
* transform the shadow to border
*/
@SuppressLint("DrawAllocation")
public class OutlineTextView extends TextView {
public OutlineTextView(Context context) {
super(context);
initPaint();
}
public OutlineTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public OutlineTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initPaint();
}
private void initPaint() {
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(getTextSize());
mTextPaint.setColor(mColor);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setTypeface(getTypeface());
mTextPaintOutline = new TextPaint();
mTextPaintOutline.setAntiAlias(true);
mTextPaintOutline.setTextSize(getTextSize());
mTextPaintOutline.setColor(mBorderColor);
mTextPaintOutline.setStyle(Paint.Style.STROKE);
mTextPaintOutline.setTypeface(getTypeface());
mTextPaintOutline.setStrokeWidth(mBorderSize);
}
public void setText(String text) {
super.setText(text);
mText = text.toString();
requestLayout();
invalidate();
}
public void setTextSize(float size) {
super.setTextSize(size);
requestLayout();
invalidate();
initPaint();
}
public void setTextColor(int color) {
super.setTextColor(color);
mColor = color;
invalidate();
initPaint();
}
public void setShadowLayer(float radius, float dx, float dy, int color) {
super.setShadowLayer(radius, dx, dy, color);
mBorderSize = radius;
mBorderColor = color;
requestLayout();
invalidate();
initPaint();
}
public void setTypeface(Typeface tf, int style) {
super.setTypeface(tf, style);
requestLayout();
invalidate();
initPaint();
}
public void setTypeface(Typeface tf) {
super.setTypeface(tf);
requestLayout();
invalidate();
initPaint();
}
@Override
protected void onDraw(Canvas canvas) {
Layout layout = new StaticLayout(getText(), mTextPaintOutline, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad);
layout.draw(canvas);
layout = new StaticLayout(getText(), mTextPaint, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad);
layout.draw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Layout layout = new StaticLayout(getText(), mTextPaintOutline, measureWidth(widthMeasureSpec), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad);
int ex = (int) (mBorderSize * 2 + 1);
setMeasuredDimension(measureWidth(widthMeasureSpec) + ex, measureHeight(heightMeasureSpec) * layout.getLineCount() + ex);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = (int) mTextPaintOutline.measureText(mText) + getPaddingLeft() + getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
mAscent = (int) mTextPaintOutline.ascent();
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = (int) (-mAscent + mTextPaintOutline.descent()) + getPaddingTop() + getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
private TextPaint mTextPaint;
private TextPaint mTextPaintOutline;
private String mText = "";
private int mAscent = 0;
private float mBorderSize;
private int mBorderColor;
private int mColor;
private float mSpacingMult = 1.0f;
private float mSpacingAdd = 0;
private boolean mIncludePad = true;
}
\ No newline at end of file
/*
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package tv.danmaku.ijk.media.widget;
/*-
* configurated by app project
*/
public class Pragma {
public static void setDebug(boolean debug) {
DebugLog.setDebug(debug);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册