CONTENT STREAM
ANDROID TRAGEDY
by Dmytro Danylyk & William Shakespeare
Dmytro Danylyk - Android Developer, Lemberg Solutions Limited
Nominated to apply for the Google Developer Expert Program
Finalist of Google Apps Developer Challenge 2012
Author of open source libraries 1000+ stars.
Big fan of android, flat design, stackoverflow, git, Intellij IDEA. Eclipse IDE hater.
@dmytrodanylyk
CHARACTERS
PREHISTORY
Montague (Developers) and Capulet (Designers) - are involved in a team feud that goes back years before any of the members were born.
ONCE UPON A TIME
Juliet meets Romeo on android project discussion where displaying video must take place.
"To Intent, or not to Intent, that is the question?" - Romeo
IMPLICIT INTENT
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("http://www.yourvideo.mp4"), "video/mp4");
String title = "Play this video with";
Intent chooser = Intent.createChooser(intent, title);
// Verify the intent will resolve to at least one activtiy
if(intent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
}
"We need a custom..." - Juliet
WHEN TO INTENT?
- when functionality is hard to implement (send email)
- when you need social sharing (facebook, twitter)
- when you don't need extra functionality (play video)
THE TRAGICAL HISTORY OF
WHAT ROMEO
THINK WILL WORK
VideoView videoView = (VideoView) findViewById(R.id.videoView);
videoView.setVideoPatn("http://www.yourvideo.mp4");
videoView.start();
"I forgot to tell..." - Juliet
"We need to make it draggable like in YouTube app"
"We need to display list of videos like in Instagram app"
"Could you remove black lines"
WELCOME TO WORLD OF BLACK PIXELS
WHAT HAPPENS WHEN YOU SCROLL
Title Text
WHAT HAPPENS WHEN YOU ANIMATE
Title Text
WHAT HAPPENS
IF YOU CROP
WHY ARE YOU DOING THIS TO ME?
"Surface view creates a new window, placed behind your application’s window, to manage content."
HOW IT WORKS?
Chestburster design pattern - make a hole in your application to inject extra functionality.
PROBLEMS
- Unexpected behavior inside scrollable container
- Unexpected behavior with animations
- No way to crop content
TEXTURE VIEW
WHEN TO USE?
- Play Video
- Stream Camera
- Render OpenGL
WHY TO USE?
"Texture View - does not create a separate window but behaves as a regular view."
"Because it uses hardware accelerated 2D rendering - it is so fast and efficient."
REQUIREMENTS
- Android 4.0 APIs
- Hardware Acceleration
QUICKSTART
BASIC LOGIC
TextureView textureView = findViewById(R.id.textureView);
textureView.setSurfaceTextureListener( new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture,
int width, int height) {
// all logic goes here
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface,
int width, int height) {
// ignore
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// ignore
}
});
VIDEO FROM ASSETS
// all logic goes here
Surface surface = new Surface(texture);
AssetFileDescriptor afd = ...
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(fileDescriptor, startOffset, length);
mMediaPlayer.setSurface(surface);
mMediaPlayer.prepareAsync();
// Play video when the media source is ready for playback.
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
CAMERA
// all logic goes here
mCamera = Camera.open();
if (mCamera == null) {
Log.d(TAG, "Your device doesn't have camera.");
return;
}
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
return true;
}
MORE INFO
- Texture View - Intro
- Texture View - Playing video
- Texture View - Video Cropping
TEXTURE VIDEO VIEW
"Texture Video View - is custom view based on android Texture View which gives you ability easily play and crop video.
WHY TO USE?
W/MediaPlayer﹕ info/warning (1, 26)
E/MediaPlayer﹕ error (1, -4)
E/MediaPlayer: error (1, -2147483648)
E/MediaPlayer﹕ start called in state 4
E/MediaPlayer﹕ error (-38, 0)
E/MediaPlayer﹕ Error (-38,0)
HOW IT LOOKS?
QUICKSTART
TextureVideoView cropTextureView =
(TextureVideoView) findViewById(R.id.cropTextureView);
// Use `setScaleType` method to crop video
cropTextureView.setScaleType(TextureVideoView.ScaleType.TOP);
// Use `setDataSource` method to set data source, this could be url, assets folder or path
cropTextureView.setDataSource("http://www.w3schools.com/html/mov_bbb.mp4");
cropTextureView.play();
WHAT INSIDE?
float scaleX = 1.0f;
float scaleY = 1.0f;
if (mVideoWidth > viewWidth && mVideoHeight > viewHeight) {
scaleX = mVideoWidth / viewWidth;
scaleY = mVideoHeight / viewHeight;
} else if (mVideoWidth < viewWidth && mVideoHeight < viewHeight) {
scaleY = viewWidth / mVideoWidth;
scaleX = viewHeight / mVideoHeight;
} else if (viewWidth > mVideoWidth) {
scaleY = (viewWidth / mVideoWidth) / (viewHeight / mVideoHeight);
} else if (viewHeight > mVideoHeight) {
scaleX = (viewHeight / mVideoHeight) / (viewWidth / mVideoWidth);
}
int pivotPointX = viewWidth / 2; // Calculate pivot points,
int pivotPointY = viewHeight / 2; // in our case crop from center
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);
mTextureView.setTransform(matrix);
MORE INFO
87
CAMERA ISSUES
PREVENT FROM APPEARING IN GOOGLE PLAY
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
CHECK IF DEVICE HAS CAMERA
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// This device has a Camera
} else {
// This device doesn't have a Camera
}
CHECK IF CAMERA IS AVAILABLE
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
} catch (Exception e) {
// Camera is not available
}
LOCK ACTIVITY SCREEN ORIENTATION
<activity android:name=".CameraActivity" android:screenOrientation="landscape" />
CALCULATE PREVIEW SIZE
Camera.Size getBestPreviewSize(int requiredWidth, int requiredHeight, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size currentSize : parameters.getSupportedPreviewSizes()) {
if (currentSize.width <= requiredWidth
&& currentSize.height <= requiredHeight) {
if (result == null) {
result = currentSize;
} else {
int resultArea = result.width * result.height;
int newArea = currentSize.width * currentSize.height;
if (newArea > resultArea) {
result = currentSize;
}
}
}
}
return result;
}
CHECK IF FEATURE IS AVAILABLE BEFORE USING IT
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// Auto-focus mode is supported
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
DON'T LOCK CAMERA FOREVER, YOU ARE NOT ALONE
@Override
protected void onPause() {
super.onPause();
// release the camera for other applications
if(mCamera != null) {
mCamera.release();
mCamera = null;
}
}
Q / A
Content Stream - Android Tragedy
By Dmytro Danylyk
Content Stream - Android Tragedy
- 4,755