Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
appinventor-sources
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
appinventor-sources
Commits
98fd7ce8
Commit
98fd7ce8
authored
Aug 20, 2012
by
Vance
Committed by
Jeffrey I. Schiller
Aug 20, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Resizable and Full Screen Video Player
Change-Id: Ica112991b56c830fcd42eb436b3921f63ce81723
parent
cba736dc
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1128 additions
and
112 deletions
+1128
-112
appinventor/appengine/src/com/google/appinventor/client/editor/simple/components/MockVideoPlayer.java
...ntor/client/editor/simple/components/MockVideoPlayer.java
+0
-4
appinventor/appengine/src/com/google/appinventor/client/youngandroid/YoungAndroidFormUpgrader.java
...nventor/client/youngandroid/YoungAndroidFormUpgrader.java
+7
-0
appinventor/blockslib/src/openblocks/yacodeblocks/BlockSaveFile.java
.../blockslib/src/openblocks/yacodeblocks/BlockSaveFile.java
+20
-15
appinventor/components/src/com/google/appinventor/components/common/YaVersion.java
...c/com/google/appinventor/components/common/YaVersion.java
+9
-5
appinventor/components/src/com/google/appinventor/components/runtime/Form.java
...s/src/com/google/appinventor/components/runtime/Form.java
+63
-1
appinventor/components/src/com/google/appinventor/components/runtime/VideoPlayer.java
...om/google/appinventor/components/runtime/VideoPlayer.java
+459
-85
appinventor/components/src/com/google/appinventor/components/runtime/util/CustomMediaController.java
...ventor/components/runtime/util/CustomMediaController.java
+118
-0
appinventor/components/src/com/google/appinventor/components/runtime/util/ErrorMessages.java
...le/appinventor/components/runtime/util/ErrorMessages.java
+9
-2
appinventor/components/src/com/google/appinventor/components/runtime/util/FullScreenVideoUtil.java
...inventor/components/runtime/util/FullScreenVideoUtil.java
+443
-0
No files found.
appinventor/appengine/src/com/google/appinventor/client/editor/simple/components/MockVideoPlayer.java
View file @
98fd7ce8
...
...
@@ -77,10 +77,6 @@ public final class MockVideoPlayer extends MockVisibleComponent {
@Override
protected
boolean
isPropertyVisible
(
String
propertyName
)
{
if
(
propertyName
.
equals
(
PROPERTY_NAME_WIDTH
)
||
propertyName
.
equals
(
PROPERTY_NAME_HEIGHT
))
{
return
false
;
}
return
super
.
isPropertyVisible
(
propertyName
);
}
}
appinventor/appengine/src/com/google/appinventor/client/youngandroid/YoungAndroidFormUpgrader.java
View file @
98fd7ce8
...
...
@@ -753,6 +753,13 @@ public final class YoungAndroidFormUpgrader {
// No properties need to be modified to upgrade to version 3.
srcCompVersion
=
3
;
}
if
(
srcCompVersion
<
4
)
{
// The VideoPlayer.height and VideoPlayer.width getter and setters were marked as
// visible to the user.
// The FullScreen property was created.
// No properties need to be modified to upgrade to version 4.
srcCompVersion
=
4
;
}
return
srcCompVersion
;
}
...
...
appinventor/blockslib/src/openblocks/yacodeblocks/BlockSaveFile.java
View file @
98fd7ce8
...
...
@@ -951,6 +951,11 @@ public class BlockSaveFile {
}
blkCompVersion
=
3
;
}
if
(
blkCompVersion
<
4
)
{
// The VideoPlayer.height and VideoPlayer.width getter and setters were marked as
// visible to the user
blkCompVersion
=
4
;
}
return
blkCompVersion
;
}
...
...
appinventor/components/src/com/google/appinventor/components/common/YaVersion.java
View file @
98fd7ce8
...
...
@@ -176,11 +176,12 @@ public class YaVersion {
// - PLAYER_COMPONENT_VERSION was incremented to 4.
// For YOUNG_ANDROID_VERSION 58:
// - FORM_COMPONENT_VERSION was incremented to 7.
// For YOUNG_ANDROID_VERSION 59:
//The Camcorder component was added.
// For YOUNG_ANDROID_VERION 59:
// The Camcorder component was added.
// For YOUNG_ANDROID_VERION 60:
// - VIDEOPLAYER_COMPONENT_VERSION was incremented to 4.
public
static
final
int
YOUNG_ANDROID_VERSION
=
59
;
public
static
final
int
YOUNG_ANDROID_VERSION
=
60
;
// ............................... Blocks Language Version Number ...............................
...
...
@@ -499,7 +500,10 @@ public class YaVersion {
// - The VideoPlayer.VideoPlayerError event was added.
// For VIDEOPLAYER_COMPONENT_VERSION 3:
// - The VideoPlayer.VideoPlayerError event was marked userVisible false and is no longer used.
public
static
final
int
VIDEOPLAYER_COMPONENT_VERSION
=
3
;
// For VIDEOPLAYER_COMPONENT_VERSION 4:
// - The VideoPlayer.width and VideoPlayer.height variables were marked as user visible.
// - The FullScreen property was added to the VideoPlayer.
public
static
final
int
VIDEOPLAYER_COMPONENT_VERSION
=
4
;
public
static
final
int
VOTING_COMPONENT_VERSION
=
1
;
...
...
appinventor/components/src/com/google/appinventor/components/runtime/Form.java
View file @
98fd7ce8
...
...
@@ -6,7 +6,6 @@ import com.google.appinventor.components.annotations.DesignerComponent;
import
com.google.appinventor.components.annotations.DesignerProperty
;
import
com.google.appinventor.components.annotations.PropertyCategory
;
import
com.google.appinventor.components.annotations.SimpleEvent
;
import
com.google.appinventor.components.annotations.SimpleFunction
;
import
com.google.appinventor.components.annotations.SimpleObject
;
import
com.google.appinventor.components.annotations.SimpleProperty
;
import
com.google.appinventor.components.annotations.UsesPermissions
;
...
...
@@ -18,6 +17,7 @@ import com.google.appinventor.components.runtime.collect.Lists;
import
com.google.appinventor.components.runtime.collect.Maps
;
import
com.google.appinventor.components.runtime.collect.Sets
;
import
com.google.appinventor.components.runtime.util.ErrorMessages
;
import
com.google.appinventor.components.runtime.util.FullScreenVideoUtil
;
import
com.google.appinventor.components.runtime.util.JsonUtil
;
import
com.google.appinventor.components.runtime.util.MediaUtil
;
import
com.google.appinventor.components.runtime.util.SdkLevel
;
...
...
@@ -25,6 +25,7 @@ import com.google.appinventor.components.runtime.util.ViewUtil;
import
android.app.Activity
;
import
android.app.AlertDialog
;
import
android.app.Dialog
;
import
android.content.ActivityNotFoundException
;
import
android.content.DialogInterface
;
import
android.content.Intent
;
...
...
@@ -131,6 +132,8 @@ public class Form extends Activity
// event.
private
String
nextFormName
;
private
FullScreenVideoUtil
fullScreenVideoUtil
;
@Override
public
void
onCreate
(
Bundle
icicle
)
{
// Called when the activity is first created
...
...
@@ -155,6 +158,8 @@ public class Form extends Activity
startupValue
=
startIntent
.
getStringExtra
(
ARGUMENT_NAME
);
}
fullScreenVideoUtil
=
new
FullScreenVideoUtil
(
this
,
androidUIHandler
);
// Add application components to the form
$define
();
...
...
@@ -350,6 +355,25 @@ public class Form extends Activity
onDestroyListeners
.
add
(
component
);
}
public
Dialog
onCreateDialog
(
int
id
,
Bundle
args
)
{
switch
(
id
)
{
case
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_DIALOG_FLAG
:
return
fullScreenVideoUtil
.
createFullScreenVideoDialog
(
args
);
default
:
return
super
.
onCreateDialog
(
id
,
args
);
}
}
public
void
onPrepareDialog
(
int
id
,
Dialog
dialog
,
Bundle
args
)
{
switch
(
id
)
{
case
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_DIALOG_FLAG
:
fullScreenVideoUtil
.
prepareFullScreenVideoDialog
(
dialog
,
args
);
break
;
default
:
super
.
onPrepareDialog
(
id
,
dialog
,
args
);
}
}
/**
* Compiler-generated method to initialize and add application components to
* the form. We just provide an implementation here to artificially make
...
...
@@ -494,6 +518,7 @@ public class Form extends Activity
if
(
backgroundDrawable
!=
null
)
{
ViewUtil
.
setBackgroundImage
(
frameLayout
,
backgroundDrawable
);
}
setContentView
(
frameLayout
);
frameLayout
.
requestLayout
();
}
...
...
@@ -1117,4 +1142,41 @@ public class Form extends Activity
throw
e
.
getTargetException
();
}
}
/**
* Perform some action related to fullscreen video display.
* @param action
* Can be any of the following:
* <ul>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_DURATION}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_FULLSCREEN}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_PAUSE}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_PLAY}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_SEEK}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_SOURCE}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_STOP}
* </li>
* </ul>
* @param source
* The VideoPlayer to use in some actions.
* @param data
* Used by the method. This object varies depending on the action.
* @return Varies depending on what action was passed in.
*/
public
synchronized
Bundle
fullScreenVideoAction
(
int
action
,
VideoPlayer
source
,
Object
data
)
{
return
fullScreenVideoUtil
.
performAction
(
action
,
source
,
data
);
}
}
appinventor/components/src/com/google/appinventor/components/runtime/VideoPlayer.java
View file @
98fd7ce8
...
...
@@ -15,12 +15,16 @@ import com.google.appinventor.components.common.ComponentConstants;
import
com.google.appinventor.components.common.PropertyTypeConstants
;
import
com.google.appinventor.components.common.YaVersion
;
import
com.google.appinventor.components.runtime.util.ErrorMessages
;
import
com.google.appinventor.components.runtime.util.FullScreenVideoUtil
;
import
com.google.appinventor.components.runtime.util.MediaUtil
;
import
android.content.Context
;
import
android.media.AudioManager
;
import
android.media.MediaPlayer
;
import
android.media.MediaPlayer.OnCompletionListener
;
import
android.media.MediaPlayer.OnErrorListener
;
import
android.media.MediaPlayer.OnPreparedListener
;
import
android.os.Bundle
;
import
android.util.Log
;
import
android.view.View
;
import
android.widget.MediaController
;
...
...
@@ -50,46 +54,64 @@ import java.io.IOException;
* things are working solidly.
*/
/**
* TODO: The resizing of the VideoPlayer at runtime does not work well on some
* devices such as the Motorola Droid. The behavior is almost random when resizing
* the VideoPlayer on such devices. When App Inventor includes the features to
* restrict certain devices, the VideoPlayer should be updated.
*/
/**
* Implementation of VideoPlayer, using {@link android.widget.VideoView}.
*
* @author halabelson@google.com (Hal Abelson)
*/
@DesignerComponent
(
version
=
YaVersion
.
VIDEOPLAYER_COMPONENT_VERSION
,
description
=
"A multimedia component capable of playing videos. "
+
"When the application is run, the VideoPlayer will be displayed as a "
+
"rectangle on-screen. If the user touches the rectangle, controls will "
+
"appear to play/pause, skip ahead, and skip backward within the video. "
+
"The application can also control behavior by calling the "
+
"<code>Start</code>, <code>Pause</code>, and <code>SeekTo</code> methods. "
+
"<p>Video files should be in Windows Media Video (.wmv) format, "
+
"3GPP (.3gp), or MPEG-4 (.mp4). For more details about legal "
+
"formats, see "
+
"<a href=\"http://developer.android.com/guide/appendix/media-formats.html\""
+
" target=\"_blank\">Android Supported Media Formats</a>.</p>"
+
"<p>App Inventor for Android only permits video files under 1 MB and "
+
"limits the total size of an application to 5 MB, not all of which is "
+
"available for media (video, audio, and sound) files. If your media "
+
"files are too large, you may get errors when packaging or installing "
+
"your application, in which case you should reduce the number of media "
+
"files or their sizes. Most video editing software, such as Windows "
+
"Movie Maker and Apple iMovie, can help you decrease the size of videos "
+
"by shortening them or re-encoding the video into a more compact format.</p>"
,
@DesignerComponent
(
version
=
YaVersion
.
VIDEOPLAYER_COMPONENT_VERSION
,
description
=
"A multimedia component capable of playing videos. "
+
"When the application is run, the VideoPlayer will be displayed as a "
+
"rectangle on-screen. If the user touches the rectangle, controls will "
+
"appear to play/pause, skip ahead, and skip backward within the video. "
+
"The application can also control behavior by calling the "
+
"<code>Start</code>, <code>Pause</code>, and <code>SeekTo</code> methods. "
+
"<p>Video files should be in Windows Media Video (.wmv) format, "
+
"3GPP (.3gp), or MPEG-4 (.mp4). For more details about legal "
+
"formats, see "
+
"<a href=\"http://developer.android.com/guide/appendix/media-formats.html\""
+
" target=\"_blank\">Android Supported Media Formats</a>.</p>"
+
"<p>App Inventor for Android only permits video files under 1 MB and "
+
"limits the total size of an application to 5 MB, not all of which is "
+
"available for media (video, audio, and sound) files. If your media "
+
"files are too large, you may get errors when packaging or installing "
+
"your application, in which case you should reduce the number of media "
+
"files or their sizes. Most video editing software, such as Windows "
+
"Movie Maker and Apple iMovie, can help you decrease the size of videos "
+
"by shortening them or re-encoding the video into a more compact format.</p>"
,
category
=
ComponentCategory
.
MEDIA
)
@SimpleObject
@UsesPermissions
(
permissionNames
=
"android.permission.INTERNET"
)
public
final
class
VideoPlayer
extends
AndroidViewComponent
implements
OnDestroyListener
,
Deleteable
,
OnCompletionListener
,
OnErrorListener
{
public
final
class
VideoPlayer
extends
AndroidViewComponent
implements
OnDestroyListener
,
Deleteable
,
OnCompletionListener
,
OnErrorListener
,
OnPreparedListener
{
/*
* Video clip with player controls (touch it to activate)
*/
private
final
VideoView
videoView
;
private
final
Resizable
VideoView
videoView
;
private
String
sourcePath
;
// name of media source
private
boolean
inFullScreen
=
false
;
// The VideoView does not always start playing if Start is called
// shortly after the source is set. These flags are used to fix this
// problem.
private
boolean
mediaReady
=
false
;
private
boolean
delayedStart
=
false
;
/**
* Creates a new VideoPlayer component.
*
...
...
@@ -98,16 +120,19 @@ public final class VideoPlayer extends AndroidViewComponent
public
VideoPlayer
(
ComponentContainer
container
)
{
super
(
container
);
container
.
$form
().
registerForOnDestroy
(
this
);
videoView
=
new
VideoView
(
container
.
$context
());
videoView
=
new
Resizable
VideoView
(
container
.
$context
());
videoView
.
setMediaController
(
new
MediaController
(
container
.
$context
()));
videoView
.
setOnCompletionListener
(
this
);
videoView
.
setOnErrorListener
(
this
);
videoView
.
setOnPreparedListener
(
this
);
// add the component to the designated container
container
.
$add
(
this
);
// set a default size
container
.
setChildWidth
(
this
,
ComponentConstants
.
VIDEOPLAYER_PREFERRED_WIDTH
);
container
.
setChildHeight
(
this
,
ComponentConstants
.
VIDEOPLAYER_PREFERRED_HEIGHT
);
container
.
setChildWidth
(
this
,
ComponentConstants
.
VIDEOPLAYER_PREFERRED_WIDTH
);
container
.
setChildHeight
(
this
,
ComponentConstants
.
VIDEOPLAYER_PREFERRED_HEIGHT
);
// Make volume buttons control media, not ringer.
container
.
$form
().
setVolumeControlStream
(
AudioManager
.
STREAM_MUSIC
);
...
...
@@ -123,20 +148,31 @@ public final class VideoPlayer extends AndroidViewComponent
/**
* Sets the video source.
*
* <p/>See {@link MediaUtil#determineMediaSource} for information about what
* a path can be.
* <p/>
* See {@link MediaUtil#determineMediaSource} for information about what a
* path can be.
*
* @param path the path to the video source
* @param path
* the path to the video source
*/
@DesignerProperty
(
editorType
=
PropertyTypeConstants
.
PROPERTY_TYPE_ASSET
,
defaultValue
=
""
)
@SimpleProperty
(
description
=
"The \"path\" to the video. Usually, this will be the "
+
"name of the video file, which should be added in the Designer."
,
description
=
"The \"path\" to the video. Usually, this will be the "
+
"name of the video file, which should be added in the Designer."
,
category
=
PropertyCategory
.
BEHAVIOR
)
public
void
Source
(
String
path
)
{
if
(
inFullScreen
)
{
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_SOURCE
,
this
,
path
);
}
else
{
sourcePath
=
(
path
==
null
)
?
""
:
path
;
// The source may change for the MediaPlayer, and
// getVideoWidth or getVideoHeight may be called
// creating an error in ResizableVideoView.
videoView
.
invalidateMediaPlayer
(
true
);
// Clear the previous video.
if
(
videoView
.
isPlaying
())
{
videoView
.
stopPlayback
();
...
...
@@ -148,6 +184,7 @@ public final class VideoPlayer extends AndroidViewComponent
Log
.
i
(
"VideoPlayer"
,
"Source path is "
+
sourcePath
);
try
{
mediaReady
=
false
;
MediaUtil
.
loadVideoView
(
videoView
,
container
.
$form
(),
sourcePath
);
}
catch
(
IOException
e
)
{
container
.
$form
().
dispatchErrorOccurredEvent
(
this
,
"Source"
,
...
...
@@ -158,26 +195,51 @@ public final class VideoPlayer extends AndroidViewComponent
Log
.
i
(
"VideoPlayer"
,
"loading video succeeded"
);
}
}
}
/**
* Plays the media specified by the source. These won't normally be used in
* the most elementary applications, because videoView brings up its own
* player controls when the video is touched.
*/
@SimpleFunction
(
description
=
"Starts playback of the video."
)
@SimpleFunction
(
description
=
"Starts playback of the video."
)
public
void
Start
()
{
Log
.
i
(
"VideoPlayer"
,
"Calling Start"
);
if
(
inFullScreen
)
{
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_PLAY
,
this
,
null
);
}
else
{
if
(
mediaReady
)
{
videoView
.
start
();
}
else
{
delayedStart
=
true
;
}
}
}
/**
* Method for starting the VideoPlayer once the media has been loaded.
* Not visible to users.
*/
public
void
delayedStart
()
{
delayedStart
=
true
;
Start
();
}
@SimpleFunction
(
description
=
"Pauses playback of the video. Playback can be resumed "
+
"at the same location by calling the <code>Start</code> method."
)
description
=
"Pauses playback of the video. Playback can be resumed "
+
"at the same location by calling the <code>Start</code> method."
)
public
void
Pause
()
{
Log
.
i
(
"VideoPlayer"
,
"Calling Pause"
);
if
(
inFullScreen
)
{
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_PAUSE
,
this
,
null
);
delayedStart
=
false
;
}
else
{
delayedStart
=
false
;
videoView
.
pause
();
}
}
@SimpleFunction
(
description
=
"Seeks to the requested time (specified in milliseconds) in the video. "
+
...
...
@@ -187,16 +249,31 @@ public final class VideoPlayer extends AndroidViewComponent
if
(
ms
<
0
)
{
ms
=
0
;
}
if
(
inFullScreen
)
{
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_SEEK
,
this
,
ms
);
}
else
{
// There is no harm if the milliseconds is longer than the duration.
videoView
.
seekTo
(
ms
);
}
}
@SimpleFunction
(
description
=
"Returns duration of the video in milliseconds."
)
public
int
GetDuration
()
{
Log
.
i
(
"VideoPlayer"
,
"Calling GetDuration"
);
if
(
inFullScreen
)
{
Bundle
result
=
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_DURATION
,
this
,
null
);
if
(
result
.
getBoolean
(
FullScreenVideoUtil
.
ACTION_SUCESS
))
{
return
result
.
getInt
(
FullScreenVideoUtil
.
ACTION_DATA
);
}
else
{
return
0
;
}
}
else
{
return
videoView
.
getDuration
();
}
}
// OnCompletionListener implementation
...
...
@@ -217,15 +294,39 @@ public final class VideoPlayer extends AndroidViewComponent
@Override
public
boolean
onError
(
MediaPlayer
m
,
int
what
,
int
extra
)
{
Log
.
e
(
"VideoPlayer"
,
"onError: what is "
+
what
+
" 0x"
+
Integer
.
toHexString
(
what
)
+
", extra is "
+
extra
+
" 0x"
+
Integer
.
toHexString
(
extra
));
// The ResizableVideoView onMeasure method attempts to use the MediaPlayer
// to measure
// the VideoPlayer; but in the event of an error, the MediaPlayer
// may report dimensions of zero video width and height.
// Since VideoPlayer currently (7/10/2012) sets its size always
// to some non-zero number, the MediaPlayer is invalidated here
// to prevent onMeasure from setting width and height as zero.
videoView
.
invalidateMediaPlayer
(
true
);
delayedStart
=
false
;
mediaReady
=
false
;
Log
.
e
(
"VideoPlayer"
,
"onError: what is "
+
what
+
" 0x"
+
Integer
.
toHexString
(
what
)
+
", extra is "
+
extra
+
" 0x"
+
Integer
.
toHexString
(
extra
));
container
.
$form
().
dispatchErrorOccurredEvent
(
this
,
"Source"
,
ErrorMessages
.
ERROR_UNABLE_TO_LOAD_MEDIA
,
sourcePath
);
return
true
;
}
@SimpleEvent
(
description
=
"The VideoPlayerError event is no longer used. "
+
"Please use the Screen.ErrorOccurred event instead."
,
@Override
public
void
onPrepared
(
MediaPlayer
newMediaPlayer
)
{
mediaReady
=
true
;
delayedStart
=
false
;
videoView
.
setMediaPlayer
(
newMediaPlayer
,
true
);
if
(
delayedStart
)
{
Start
();
}
}
@SimpleEvent
(
description
=
"The VideoPlayerError event is no longer used. "
+
"Please use the Screen.ErrorOccurred event instead."
,
userVisible
=
false
)
public
void
VideoPlayerError
(
String
message
)
{
}
...
...
@@ -250,21 +351,26 @@ public final class VideoPlayer extends AndroidViewComponent
}
videoView
.
setVideoURI
(
null
);
videoView
.
clearAnimation
();
}
/*
* Unfortunately, to prevent the user from setting the width and height
* of the component, we have to also prevent them from getting the width
* and height of the component.
*/
delayedStart
=
false
;
mediaReady
=
false
;
if
(
inFullScreen
)
{
Bundle
data
=
new
Bundle
();
data
.
putBoolean
(
FullScreenVideoUtil
.
VIDEOPLAYER_FULLSCREEN
,
false
);
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_FULLSCREEN
,
this
,
data
);
}
}
/**
* Returns the component's horizontal width, measured in pixels.
*
* @return width in pixels
*/
@Override
@SimpleProperty
(
userVisible
=
false
)
@SimpleProperty
public
int
Width
()
{
return
super
.
Width
();
}
...
...
@@ -274,10 +380,14 @@ public final class VideoPlayer extends AndroidViewComponent
*
* @param width in pixels
*/
@Override
@SimpleProperty
(
userVisible
=
fals
e
)
@SimpleProperty
(
userVisible
=
tru
e
)
public
void
Width
(
int
width
)
{
super
.
Width
(
width
);
// Forces a layout of the ResizableVideoView
videoView
.
changeVideoSize
(
width
,
videoView
.
forcedHeight
);
}
/**
...
...
@@ -285,8 +395,9 @@ public final class VideoPlayer extends AndroidViewComponent
*
* @return height in pixels
*/
@Override
@SimpleProperty
(
userVisible
=
false
)
@SimpleProperty
public
int
Height
()
{
return
super
.
Height
();
}
...
...
@@ -294,11 +405,274 @@ public final class VideoPlayer extends AndroidViewComponent
/**
* Specifies the component's vertical height, measured in pixels.
*
* @param height in pixels
* @param height
* in pixels
*/
@Override
@SimpleProperty
(
userVisible
=
fals
e
)
@SimpleProperty
(
userVisible
=
tru
e
)
public
void
Height
(
int
height
)
{
super
.
Height
(
height
);
// Forces a layout of the ResizableVideoView
videoView
.
changeVideoSize
(
videoView
.
forcedWidth
,
height
);
}
/**
* Returns whether the VideoPlayer's video is currently being
* shown in fullscreen mode or not.
* @return True if video is being shown in fullscreen. False otherwise.
*/
@SimpleProperty
public
boolean
FullScreen
()
{
return
inFullScreen
;
}
/**
* Sets whether the video should be shown in fullscreen or not.
*
* @param value If True, the video will be shown in fullscreen.
* If False and {@link VideoPlayer#FullScreen()} returns True, fullscreen
* mode will be exited. If False and {@link VideoPlayer#FullScreen()}
* returns False, nothing occurs.
*/
@SimpleProperty
(
userVisible
=
true
)
public
void
FullScreen
(
boolean
value
)
{
if
(
value
!=
inFullScreen
)
{
if
(
value
)
{
Bundle
data
=
new
Bundle
();
data
.
putInt
(
FullScreenVideoUtil
.
VIDEOPLAYER_POSITION
,
videoView
.
getCurrentPosition
());
data
.
putBoolean
(
FullScreenVideoUtil
.
VIDEOPLAYER_PLAYING
,
videoView
.
isPlaying
());
videoView
.
pause
();
data
.
putBoolean
(
FullScreenVideoUtil
.
VIDEOPLAYER_FULLSCREEN
,
true
);
data
.
putString
(
FullScreenVideoUtil
.
VIDEOPLAYER_SOURCE
,
sourcePath
);
Bundle
result
=
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_FULLSCREEN
,
this
,
data
);
if
(
result
.
getBoolean
(
FullScreenVideoUtil
.
ACTION_SUCESS
))
{
inFullScreen
=
true
;
}
else
{
inFullScreen
=
false
;
container
.
$form
().
dispatchErrorOccurredEvent
(
this
,
"FullScreen"
,
ErrorMessages
.
ERROR_VIDEOPLAYER_FULLSCREEN_UNAVAILBLE
,
""
);
}
}
else
{
Bundle
values
=
new
Bundle
();
values
.
putBoolean
(
FullScreenVideoUtil
.
VIDEOPLAYER_FULLSCREEN
,
false
);
Bundle
result
=
container
.
$form
().
fullScreenVideoAction
(
FullScreenVideoUtil
.
FULLSCREEN_VIDEO_ACTION_FULLSCREEN
,
this
,
values
);
if
(
result
.
getBoolean
(
FullScreenVideoUtil
.
ACTION_SUCESS
))
{
fullScreenKilled
((
Bundle
)
result
);
}
else
{
inFullScreen
=
true
;
container
.
$form
().
dispatchErrorOccurredEvent
(
this
,
"FullScreen"
,
ErrorMessages
.
ERROR_VIDEOPLAYER_FULLSCREEN_CANT_EXIT
,
""
);
}
}
}
}
/**
* Notify this VideoPlayer that its video is no longer being shown
* in fullscreen.
* @param data See {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil}
* for an example of what data should contain.
*/
public
void
fullScreenKilled
(
Bundle
data
)
{
inFullScreen
=
false
;
String
newSource
=
data
.
getString
(
FullScreenVideoUtil
.
VIDEOPLAYER_SOURCE
);
if
(!
newSource
.
equals
(
sourcePath
))
{
Source
(
newSource
);
}
videoView
.
setVisibility
(
View
.
VISIBLE
);
videoView
.
requestLayout
();
SeekTo
(
data
.
getInt
(
FullScreenVideoUtil
.
VIDEOPLAYER_POSITION
));
if
(
data
.
getBoolean
(
FullScreenVideoUtil
.
VIDEOPLAYER_PLAYING
))
{
Start
();
}
}
/**
* Get the value passed in {@link VideoPlayer#Width(int)}
* @return The width value.
*/
public
int
getPassedWidth
()
{
return
videoView
.
forcedWidth
;
}
/**
* Get the value passed in {@link VideoPlayer#Height(int)}
* @return The height value.
*/
public
int
getPassedHeight
()
{
return
videoView
.
forcedHeight
;
}
/**
* Extends VideoView to allow resizing of the view that ignores the aspect
* ratio of the video being played.
*
* @author Vance Turnewitsch
*/
class
ResizableVideoView
extends
VideoView
{
private
MediaPlayer
mVideoPlayer
;
/*
* Used by onMeasure to determine whether the mVideoPlayer should be used to
* measure the view.
*/
private
Boolean
mFoundMediaPlayer
=
false
;
/**
* Used by onMeasure to determine what type of size the VideoPlayer should
* be.
*/
public
int
forcedWidth
=
LENGTH_PREFERRED
;
/**
* Used by onMeasure to determine what type of size the VideoPlayer should
* be.
*/
public
int
forcedHeight
=
LENGTH_PREFERRED
;
public
ResizableVideoView
(
Context
context
)
{
super
(
context
);
}
public
void
onMeasure
(
int
specwidth
,
int
specheight
)
{
// Since super.onMeasure uses the aspect ratio of the video being
// played, it is not called.
// http://grepcode.com/file/repository.grepcode.com/java/ext/
// com.google.android/android/2.2.2_r1/android/widget/VideoView.java
// #VideoView.onMeasure%28int%2Cint%29
// Log messages in this method are not commented out for testing the
// changes
// on other devices.
Log
.
i
(
"VideoPlayer..onMeasure"
,
"AI setting dimensions as:"
+
forcedWidth
+
":"
+
forcedHeight
);
Log
.
i
(
"VideoPlayer..onMeasure"
,
"Dimenions from super>>"
+
MeasureSpec
.
getSize
(
specwidth
)
+
":"
+
MeasureSpec
.
getSize
(
specheight
));
// The VideoPlayer's dimensions must always be some non-zero number.
int
width
=
ComponentConstants
.
VIDEOPLAYER_PREFERRED_WIDTH
;
int
height
=
ComponentConstants
.
VIDEOPLAYER_PREFERRED_HEIGHT
;
switch
(
forcedWidth
)
{
case
LENGTH_FILL_PARENT:
switch
(
MeasureSpec
.
getMode
(
specwidth
))
{
case
MeasureSpec
.
EXACTLY
:
case
MeasureSpec
.
AT_MOST
:
width
=
MeasureSpec
.
getSize
(
specwidth
);
break
;
case
MeasureSpec
.
UNSPECIFIED
:
try
{
width
=
((
View
)
getParent
()).
getMeasuredWidth
();
}
catch
(
ClassCastException
cast
)
{
width
=
ComponentConstants
.
VIDEOPLAYER_PREFERRED_WIDTH
;
}
catch
(
NullPointerException
nullParent
)
{
width
=
ComponentConstants
.
VIDEOPLAYER_PREFERRED_WIDTH
;
}
}
break
;
case
LENGTH_PREFERRED:
if
(
mFoundMediaPlayer
)
{
try
{
width
=
mVideoPlayer
.
getVideoWidth
();
Log
.
i
(
"VideoPlayer.onMeasure"
,
"Got width from MediaPlayer>"
+
width
);
}
catch
(
NullPointerException
nullVideoPlayer
)
{
Log
.
e
(
"VideoPlayer..onMeasure"
,
"Failed to get MediaPlayer for width:\n"
+
nullVideoPlayer
.
getMessage
());
width
=
ComponentConstants
.
VIDEOPLAYER_PREFERRED_WIDTH
;
}
}
else
{
}
break
;
default
:
width
=
forcedWidth
;
}
switch
(
forcedHeight
)
{
case
LENGTH_FILL_PARENT:
switch
(
MeasureSpec
.
getMode
(
specheight
))
{
case
MeasureSpec
.
EXACTLY
:
case
MeasureSpec
.
AT_MOST
:
height
=
MeasureSpec
.
getSize
(
specheight
);
break
;
case
MeasureSpec
.
UNSPECIFIED
:
// Use height from ComponentConstants
// The current measuring of components ignores FILL_PARENT for height,
// and does not actually fill the height of the parent container.
}
break
;
case
LENGTH_PREFERRED:
if
(
mFoundMediaPlayer
)
{
try
{
height
=
mVideoPlayer
.
getVideoHeight
();
Log
.
i
(
"VideoPlayer.onMeasure"
,
"Got height from MediaPlayer>"
+
height
);
}
catch
(
NullPointerException
nullVideoPlayer
)
{
Log
.
e
(
"VideoPlayer..onMeasure"
,
"Failed to get MediaPlayer for height:\n"
+
nullVideoPlayer
.
getMessage
());
height
=
ComponentConstants
.
VIDEOPLAYER_PREFERRED_HEIGHT
;
}
}
break
;
default
:
height
=
forcedHeight
;
}
// Forces the video playing in the VideoView to scale.
// Some Android devices though will not scale the video playing.
Log
.
i
(
"VideoPlayer.onMeasure"
,
"Setting dimensions to:"
+
width
+
"x"
+
height
);
getHolder
().
setFixedSize
(
width
,
height
);
setMeasuredDimension
(
width
,
height
);
}
/**
* Resize the view size and request a layout.
*/
public
void
changeVideoSize
(
int
newWidth
,
int
newHeight
)
{
forcedWidth
=
newWidth
;
forcedHeight
=
newHeight
;
forceLayout
();
invalidate
();
}
/*
* Used to keep onMeasure from using the mVideoPlayer in measuring.
*/
public
void
invalidateMediaPlayer
(
boolean
triggerRedraw
)
{
mFoundMediaPlayer
=
false
;
mVideoPlayer
=
null
;
if
(
triggerRedraw
)
{
forceLayout
();
invalidate
();
}
}
public
void
setMediaPlayer
(
MediaPlayer
newMediaPlayer
,
boolean
triggerRedraw
)
{
mVideoPlayer
=
newMediaPlayer
;
mFoundMediaPlayer
=
true
;
if
(
triggerRedraw
)
{
forceLayout
();
invalidate
();
}
}
}
}
appinventor/components/src/com/google/appinventor/components/runtime/util/CustomMediaController.java
0 → 100644
View file @
98fd7ce8
// Copyright MIT
package
com.google.appinventor.components.runtime.util
;
import
android.content.Context
;
import
android.util.Log
;
import
android.view.MotionEvent
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.widget.MediaController
;
/**
* A modified MediaController that allows adding to a
* {@link android.view.ViewGroup} instead of the Window that Android adds the
* MediaController to.
*
* This class manages displaying the controller GUI.
*
* @author Vance Turnewitsch
*
*/
public
class
CustomMediaController
extends
MediaController
implements
View
.
OnTouchListener
{
// The view whose touch events are listened to.
private
View
mAnchorView
;
/*
* How long the GUI should be shown when the anchorView passed in
*/
private
int
mShowTime
=
3000
;
public
CustomMediaController
(
Context
context
)
{
super
(
context
);
}
/**
* Sets the visibility of the GUI to {@link android.view.View#VISIBLE}
* and calls {@link android.widget.MediaController#show(int)}.
* @param timeout
* How long the GUI should be shown for.
*/
@Override
public
void
show
(
int
timeout
)
{
setVisibility
(
VISIBLE
);
super
.
show
(
timeout
);
}
/**
* Sets the visibility of the GUI to {@link android.view.View#VISIBLE}
* and calls {@link android.widget.MediaController#show()}.
*/
@Override
public
void
show
()
{
setVisibility
(
VISIBLE
);
super
.
show
();
}
/**
* Attempts to remove this CustomMediaController from the Window that Android
* automatically adds it to and add it to another
* {@link android.view.ViewGroup}.
*
* @param parent
* The {@link android.view.ViewGroup} to add the CustomMediaController
* to.
* @param params
* The {@link android.view.ViewGroup.LayoutParams} to use when adding
* the CustomMediaController to the parent.
*/
public
boolean
addTo
(
ViewGroup
parent
,
ViewGroup
.
LayoutParams
params
)
{
Object
mParent
=
getParent
();
if
(
mParent
!=
null
&&
mParent
instanceof
ViewGroup
)
{
((
ViewGroup
)
mParent
).
removeView
(
this
);
parent
.
addView
(
this
,
params
);
return
true
;
}
else
{
Log
.
e
(
"CustomMediaController.addTo"
,
"MediaController not available in fullscreen."
);
return
false
;
}
}
/**
* Calls {@link android.widget.MediaController#setAnchorView(View)} and sets
* up a listener that shows a GUI when the anchorView is touched.
*/
@Override
public
void
setAnchorView
(
View
anchorView
)
{
mAnchorView
=
anchorView
;
mAnchorView
.
setOnTouchListener
(
this
);
super
.
setAnchorView
(
anchorView
);
}
/**
* Calls {@link android.widget.MediaController#hide()} and sets the visibility
* of this object to {@link android.view.View#INVISIBLE}.
*/
@Override
public
void
hide
()
{
super
.
hide
();
setVisibility
(
INVISIBLE
);
}
/**
* Called when the anchorView passed in
* {@link CustomMediaController#setAnchorView(View)} is touched. Shows the
* controller GUI.
*/
@Override
public
boolean
onTouch
(
View
v
,
MotionEvent
event
)
{
if
(
v
==
mAnchorView
)
{
show
(
mShowTime
);
}
return
false
;
}
}
appinventor/components/src/com/google/appinventor/components/runtime/util/ErrorMessages.java
View file @
98fd7ce8
...
...
@@ -115,8 +115,10 @@ public final class ErrorMessages {
public
static
final
int
ERROR_PHONE_UNSUPPORTED_SEARCH_IN_CONTACT_PICKING
=
1108
;
//Camcorder errors
public
static
final
int
ERROR_CAMCORDER_NO_CLIP_RETURNED
=
1201
;
// Please start the next group of error numbers at 1301.
// VideoPlayer errors
public
static
final
int
ERROR_VIDEOPLAYER_FULLSCREEN_UNAVAILBLE
=
1301
;
public
static
final
int
ERROR_VIDEOPLAYER_FULLSCREEN_CANT_EXIT
=
1302
;
//Please start the next group of error numbers at 1401.
// Mapping of error numbers to error message format strings.
private
static
final
Map
<
Integer
,
String
>
errorMessages
;
...
...
@@ -315,6 +317,11 @@ public final class ErrorMessages {
// Camcorder errors
errorMessages
.
put
(
ERROR_CAMCORDER_NO_CLIP_RETURNED
,
"The camcorder did not return a clip."
);
// VideoPlayer errors
errorMessages
.
put
(
ERROR_VIDEOPLAYER_FULLSCREEN_UNAVAILBLE
,
"Cannot start fullscreen mode."
);
errorMessages
.
put
(
ERROR_VIDEOPLAYER_FULLSCREEN_CANT_EXIT
,
"Cannot exit fullscreen mode."
);
}
private
ErrorMessages
()
{
...
...
appinventor/components/src/com/google/appinventor/components/runtime/util/FullScreenVideoUtil.java
0 → 100644
View file @
98fd7ce8
// Copyright MIT
package
com.google.appinventor.components.runtime.util
;
import
com.google.appinventor.components.runtime.Form
;
import
com.google.appinventor.components.runtime.VideoPlayer
;
import
android.R
;
import
android.app.Dialog
;
import
android.content.DialogInterface
;
import
android.content.DialogInterface.OnShowListener
;
import
android.media.MediaPlayer
;
import
android.media.MediaPlayer.OnCompletionListener
;
import
android.media.MediaPlayer.OnPreparedListener
;
import
android.os.Bundle
;
import
android.os.Handler
;
import
android.util.Log
;
import
android.view.Gravity
;
import
android.view.MotionEvent
;
import
android.view.View
;
import
android.view.View.OnTouchListener
;
import
android.view.ViewGroup
;
import
android.view.ViewGroup.LayoutParams
;
import
android.widget.FrameLayout
;
import
android.widget.VideoView
;
import
java.io.IOException
;
/**
* Used by the {@link com.google.appinventor.components.runtime.Form} class to
* display videos in fullscreen.
*
* @author Vance Turnewitsch
*/
public
class
FullScreenVideoUtil
implements
OnCompletionListener
,
OnPreparedListener
,
OnShowListener
{
// Constants
public
static
final
int
FULLSCREEN_VIDEO_DIALOG_FLAG
=
189
;
public
static
final
int
FULLSCREEN_VIDEO_ACTION_SEEK
=
190
;
public
static
final
int
FULLSCREEN_VIDEO_ACTION_PLAY
=
191
;
public
static
final
int
FULLSCREEN_VIDEO_ACTION_PAUSE
=
192
;
public
static
final
int
FULLSCREEN_VIDEO_ACTION_STOP
=
193
;
public
static
final
int
FULLSCREEN_VIDEO_ACTION_SOURCE
=
194
;
public
static
final
int
FULLSCREEN_VIDEO_ACTION_FULLSCREEN
=
195
;
public
static
final
int
FULLSCREEN_VIDEO_ACTION_DURATION
=
196
;
public
static
final
String
VIDEOPLAYER_FULLSCREEN
=
"FullScreenKey"
;
public
static
final
String
VIDEOPLAYER_PLAYING
=
"PlayingKey"
;
public
static
final
String
VIDEOPLAYER_POSITION
=
"PositionKey"
;
public
static
final
String
VIDEOPLAYER_SOURCE
=
"SourceKey"
;
public
static
final
String
ACTION_SUCESS
=
"ActionSuccess"
;
public
static
final
String
ACTION_DATA
=
"ActionData"
;
// The Dialog and other components used in the Dialog for displaying the
// video.
private
Dialog
mFullScreenVideoDialog
;
private
FrameLayout
mFullScreenVideoHolder
;
private
VideoView
mFullScreenVideoView
;
private
CustomMediaController
mFullScreenVideoController
;
private
FrameLayout
.
LayoutParams
mMediaControllerParams
=
new
FrameLayout
.
LayoutParams
(
LayoutParams
.
FILL_PARENT
,
LayoutParams
.
WRAP_CONTENT
,
Gravity
.
BOTTOM
);
private
Form
mForm
;
// The player whose video is currently being shown.
private
VideoPlayer
mFullScreenPlayer
=
null
;
// The data passed in by the player that requested
// fullscreen display of its video.
private
Bundle
mFullScreenVideoBundle
;
// Used for showing a preview of a paused video.
private
Handler
mHandler
;
/**
* @param form
* The {@link com.google.appinventor.components.runtime.Form} that
* this FullScreenVideoUtil will use.
* @param handler
* A {@link android.os.Handler} created on the UI thread. Used for
* displaying a preview of a paused video.
*/
public
FullScreenVideoUtil
(
Form
form
,
Handler
handler
)
{
mForm
=
form
;
mHandler
=
handler
;
mFullScreenVideoDialog
=
new
Dialog
(
mForm
,
R
.
style
.
Theme_NoTitleBar_Fullscreen
)
{
public
void
onBackPressed
()
{
// Allows the user to force exiting full-screen.
Bundle
values
=
new
Bundle
();
values
.
putInt
(
VIDEOPLAYER_POSITION
,
mFullScreenVideoView
.
getCurrentPosition
());
values
.
putBoolean
(
VIDEOPLAYER_PLAYING
,
mFullScreenVideoView
.
isPlaying
());
values
.
putString
(
VIDEOPLAYER_SOURCE
,
mFullScreenVideoBundle
.
getString
(
VIDEOPLAYER_SOURCE
));
mFullScreenPlayer
.
fullScreenKilled
(
values
);
super
.
onBackPressed
();
}
};
}
/**
* Perform some action and get a result. The data to pass in and the result
* returned are controlled by what the action is.
*
* @param action
* Can be any of the following:
* <ul>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_DURATION}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_FULLSCREEN}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_PAUSE}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_PLAY}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_SEEK}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_SOURCE}
* </li>
* <li>
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#FULLSCREEN_VIDEO_ACTION_STOP}
* </li>
* </ul>
* @param source
* The VideoPlayer to use in some actions.
* @param data
* Used by the method. This object varies depending on the action.
* @return Varies depending on what action was passed in.
*/
public
synchronized
Bundle
performAction
(
int
action
,
VideoPlayer
source
,
Object
data
)
{
Log
.
i
(
"Form.fullScreenVideoAction"
,
"Actions:"
+
action
+
" Source:"
+
source
+
": Current Source:"
+
mFullScreenPlayer
+
" Data:"
+
data
);
Bundle
result
=
new
Bundle
();
result
.
putBoolean
(
ACTION_SUCESS
,
true
);
if
(
source
==
mFullScreenPlayer
)
{
switch
(
action
)
{
case
FULLSCREEN_VIDEO_ACTION_FULLSCREEN:
return
doFullScreenVideoAction
(
source
,
(
Bundle
)
data
);
case
FULLSCREEN_VIDEO_ACTION_PAUSE:
if
(
showing
())
{
mFullScreenVideoView
.
pause
();
return
result
;
}
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
case
FULLSCREEN_VIDEO_ACTION_PLAY:
if
(
showing
())
{
mFullScreenVideoView
.
start
();
return
result
;
}
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
case
FULLSCREEN_VIDEO_ACTION_SEEK:
if
(
showing
())
{
mFullScreenVideoView
.
seekTo
((
Integer
)
data
);
return
result
;
}
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
case
FULLSCREEN_VIDEO_ACTION_STOP:
if
(
showing
())
{
mFullScreenVideoView
.
stopPlayback
();
return
result
;
}
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
case
FULLSCREEN_VIDEO_ACTION_SOURCE:
if
(
showing
())
{
result
.
putBoolean
(
ACTION_SUCESS
,
setSource
((
String
)
data
,
true
));
return
result
;
}
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
case
FULLSCREEN_VIDEO_ACTION_DURATION:
if
(
showing
())
{
result
.
putInt
(
ACTION_DATA
,
mFullScreenVideoView
.
getDuration
());
return
result
;
}
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
}
}
else
if
(
action
==
FULLSCREEN_VIDEO_ACTION_FULLSCREEN
)
{
// There may be a dialog already being shown.
if
(
showing
()
&&
mFullScreenPlayer
!=
null
)
{
Bundle
values
=
new
Bundle
();
values
.
putInt
(
VIDEOPLAYER_POSITION
,
mFullScreenVideoView
.
getCurrentPosition
());
values
.
putBoolean
(
VIDEOPLAYER_PLAYING
,
mFullScreenVideoView
.
isPlaying
());
values
.
putString
(
VIDEOPLAYER_SOURCE
,
mFullScreenVideoBundle
.
getString
(
VIDEOPLAYER_SOURCE
));
mFullScreenPlayer
.
fullScreenKilled
(
values
);
}
return
doFullScreenVideoAction
(
source
,
(
Bundle
)
data
);
}
// This should never be called.
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
}
/*
* Displays or hides a full-screen video.
*/
private
Bundle
doFullScreenVideoAction
(
VideoPlayer
source
,
Bundle
data
)
{
Log
.
i
(
"Form.doFullScreenVideoAction"
,
"Source:"
+
source
+
" Data:"
+
data
);
Bundle
result
=
new
Bundle
();
result
.
putBoolean
(
ACTION_SUCESS
,
true
);
if
(
data
.
getBoolean
(
VIDEOPLAYER_FULLSCREEN
)
==
true
)
{
mFullScreenPlayer
=
source
;
mFullScreenVideoBundle
=
data
;
if
(!
mFullScreenVideoDialog
.
isShowing
())
{
mForm
.
showDialog
(
FULLSCREEN_VIDEO_DIALOG_FLAG
,
(
Bundle
)
data
);
return
result
;
}
else
{
mFullScreenVideoView
.
pause
();
result
.
putBoolean
(
ACTION_SUCESS
,
setSource
(
mFullScreenVideoBundle
.
getString
(
VIDEOPLAYER_SOURCE
),
false
));
return
result
;
}
}
else
{
if
(
showing
())
{
result
.
putBoolean
(
VIDEOPLAYER_PLAYING
,
mFullScreenVideoView
.
isPlaying
());
result
.
putInt
(
VIDEOPLAYER_POSITION
,
mFullScreenVideoView
.
getCurrentPosition
());
result
.
putString
(
VIDEOPLAYER_SOURCE
,
mFullScreenVideoBundle
.
getString
(
VIDEOPLAYER_SOURCE
));
mFullScreenPlayer
=
null
;
mFullScreenVideoBundle
=
null
;
mForm
.
dismissDialog
(
FULLSCREEN_VIDEO_DIALOG_FLAG
);
return
result
;
}
}
result
.
putBoolean
(
ACTION_SUCESS
,
false
);
return
result
;
}
/**
* Creates the dialog for displaying a fullscreen VideoView.
*
* @param data
* The data to be used by this class in displaying the fullscreen
* video.
* @return The created Dialog
*/
public
Dialog
createFullScreenVideoDialog
(
final
Bundle
data
)
{
mFullScreenVideoBundle
=
data
;
mFullScreenVideoView
=
new
VideoView
(
mForm
);
mFullScreenVideoHolder
=
new
FrameLayout
(
mForm
);
mFullScreenVideoController
=
new
CustomMediaController
(
mForm
);
mFullScreenVideoView
.
setId
(
mFullScreenVideoView
.
hashCode
());
mFullScreenVideoHolder
.
setId
(
mFullScreenVideoHolder
.
hashCode
());
mFullScreenVideoView
.
setMediaController
(
mFullScreenVideoController
);
mFullScreenVideoView
.
setOnTouchListener
(
new
OnTouchListener
()
{
@Override
public
boolean
onTouch
(
View
arg0
,
MotionEvent
arg1
)
{
Log
.
i
(
"FullScreenVideoUtil..onTouch"
,
"Video Touched!!"
);
return
false
;
}
});
mFullScreenVideoController
.
setAnchorView
(
mFullScreenVideoView
);
String
orientation
=
mForm
.
ScreenOrientation
();
if
(
orientation
.
equals
(
"landscape"
)
||
orientation
.
equals
(
"sensorLandscape"
)
||
orientation
.
equals
(
"reverseLandscape"
))
{
mFullScreenVideoView
.
setLayoutParams
(
new
FrameLayout
.
LayoutParams
(
FrameLayout
.
LayoutParams
.
WRAP_CONTENT
,
FrameLayout
.
LayoutParams
.
FILL_PARENT
,
Gravity
.
CENTER
));
}
else
{
mFullScreenVideoView
.
setLayoutParams
(
new
FrameLayout
.
LayoutParams
(
FrameLayout
.
LayoutParams
.
FILL_PARENT
,
FrameLayout
.
LayoutParams
.
WRAP_CONTENT
,
Gravity
.
CENTER
));
}
mFullScreenVideoHolder
.
setLayoutParams
(
new
ViewGroup
.
LayoutParams
(
ViewGroup
.
LayoutParams
.
FILL_PARENT
,
ViewGroup
.
LayoutParams
.
FILL_PARENT
));
mFullScreenVideoHolder
.
addView
(
mFullScreenVideoView
);
// Add the MediaController to the Dialog
mFullScreenVideoController
.
addTo
(
mFullScreenVideoHolder
,
mMediaControllerParams
);
mFullScreenVideoDialog
.
setContentView
(
mFullScreenVideoHolder
);
return
mFullScreenVideoDialog
;
}
/**
* Call just before displaying a fullscreen video Dialog. This method
* sets up some listeners.
*
* @param dia
* The dialog that will display the video.
* @param data
*/
public
void
prepareFullScreenVideoDialog
(
Dialog
dia
,
Bundle
data
)
{
dia
.
setOnShowListener
(
this
);
mFullScreenVideoView
.
setOnPreparedListener
(
this
);
mFullScreenVideoView
.
setOnCompletionListener
(
this
);
}
/**
* @return True if the internal Dialog has been created. False otherwise.
*/
public
boolean
dialogInitialized
()
{
return
mFullScreenVideoDialog
!=
null
;
}
/**
* @return True if {@link FullScreenVideoUtil#dialogInitialized()} is true and
* the Dialog is showing. False otherwise.
*/
public
boolean
showing
()
{
return
dialogInitialized
()
&&
mFullScreenVideoDialog
.
isShowing
();
}
/**
* Sets the source to be used by the fullscreen video Dialog. This method
* also attempts to load the internal VideoView with the source.
*
* @param source
* The source path to use. The {@link MediaUtil} is used to load the
* source.
* @param clearSeek
* If True, the video will start playing at position zero. If False,
* the video will start playing from the
* {@link com.google.appinventor.components.runtime.util.FullScreenVideoUtil#VIDEOPLAYER_POSITION}
* value of the Bundle passed in the
* {@link FullScreenVideoUtil#performAction(int, VideoPlayer, Object)}
* or {@link FullScreenVideoUtil#createFullScreenVideoDialog(Bundle)}
* @return True if the video was successfully loaded. False otherwise.
*/
public
boolean
setSource
(
String
source
,
boolean
clearSeek
)
{
try
{
if
(
clearSeek
)
{
mFullScreenVideoBundle
.
putInt
(
VIDEOPLAYER_POSITION
,
0
);
}
MediaUtil
.
loadVideoView
(
mFullScreenVideoView
,
mForm
,
(
String
)
source
);
mFullScreenVideoBundle
.
putString
(
VIDEOPLAYER_SOURCE
,
source
);
return
true
;
}
catch
(
IOException
e
)
{
mForm
.
dispatchErrorOccurredEvent
(
mFullScreenPlayer
,
"Source"
,
ErrorMessages
.
ERROR_UNABLE_TO_LOAD_MEDIA
,
source
);
return
false
;
}
}
/**
* Called when the video has finished playing.
*/
@Override
public
void
onCompletion
(
MediaPlayer
arg0
)
{
if
(
mFullScreenPlayer
!=
null
)
{
mFullScreenPlayer
.
Completed
();
}
}
/**
* Called when the video has been loaded.
*/
@Override
public
void
onPrepared
(
MediaPlayer
arg0
)
{
Log
.
i
(
"FullScreenVideoUtil..onPrepared"
,
"Seeking to:"
+
mFullScreenVideoBundle
.
getInt
(
VIDEOPLAYER_POSITION
));
mFullScreenVideoView
.
seekTo
(
mFullScreenVideoBundle
.
getInt
(
VIDEOPLAYER_POSITION
));
if
(
mFullScreenVideoBundle
.
getBoolean
(
VIDEOPLAYER_PLAYING
))
{
mFullScreenVideoView
.
start
();
}
else
{
mFullScreenVideoView
.
start
();
mHandler
.
postDelayed
(
new
Runnable
()
{
@Override
public
void
run
()
{
mFullScreenVideoView
.
pause
();
}
},
100
);
}
}
/**
* Called when the Dialog is about to be shown.
*/
@Override
public
void
onShow
(
DialogInterface
arg0
)
{
try
{
MediaUtil
.
loadVideoView
(
mFullScreenVideoView
,
mForm
,
mFullScreenVideoBundle
.
getString
(
VIDEOPLAYER_SOURCE
));
}
catch
(
IOException
e
)
{
mForm
.
dispatchErrorOccurredEvent
(
mFullScreenPlayer
,
"Source"
,
ErrorMessages
.
ERROR_UNABLE_TO_LOAD_MEDIA
,
mFullScreenVideoBundle
.
getString
(
VIDEOPLAYER_SOURCE
));
return
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment