Search code examples
androidandroid-videoviewdaydream

VideoView and MediaController within a DayDream?


I got the following exception:

02-10 15:30:03.676  12841-12841/hu.stuff.dreamE/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: hu.stuff.dream, PID: 12841
    android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
            at android.view.ViewRootImpl.setView(ViewRootImpl.java:536)
            at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:259)
            at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
            at android.app.Dialog.show(Dialog.java:286)
            at android.app.AlertDialog$Builder.show(AlertDialog.java:951)
            at android.widget.VideoView$5.onError(VideoView.java:516)
            at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:2248)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5034)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:731)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
            at dalvik.system.NativeStart.main(Native Method)

For the following code:

public class MyDreamService extends DreamService {
    VideoView vidView;

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        setInteractive(false);
        setFullscreen(true);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onDreamingStarted() {
        super.onDreamingStarted();
        vidView = (VideoView)findViewById(R.id.myVideo);
        vidView.setVideoPath("Voice_Activated_Corgi.mp4");
        vidView.start();
    }

    @Override
    public void onDreamingStopped() {
        super.onDreamingStopped();
        vidView.stopPlayback();
    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    }
}

Quite obviously, the problem is that this is not an Activity context, this is a Window within a DreamService. I don't really want to start an Activity from the service (that'd ruin the point of the daydream, wouldn't it?) but I also don't really want to reimplement the VideoView.

Although I'm most likely going to have to go another route instead of VideoView and hope they don't use Dialogs underneath (MediaPlayer and SurfaceView).

Any ideas on how to fix the problem of using VideoView in a DreamService's Window without getting BadTokenException?


Solution

  • The MediaPlayer and SurfaceView approach worked.

    public class MyDreamService extends DreamService implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener {
        private MediaPlayer mediaPlayer;
        private SurfaceHolder vidHolder;
        private SurfaceView vidSurface;
    
        @Override
        public void onAttachedToWindow() {
            super.onAttachedToWindow();
            setInteractive(false);
            setFullscreen(true);
            setContentView(R.layout.activity_main);
            vidSurface = (SurfaceView) findViewById(R.id.surfView);
            vidHolder = vidSurface.getHolder();
            vidHolder.addCallback(this);
        }
    
        @Override
        public void onDreamingStarted() {
            super.onDreamingStarted();
        }
    
        @Override
        public void onDreamingStopped() {
            super.onDreamingStopped();
            if(mediaPlayer.isPlaying()) {
                mediaPlayer.stop();
            }
        }
    
        @Override
        public void onDetachedFromWindow() {
            super.onDetachedFromWindow();
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                mediaPlayer = MediaPlayer.create(this, R.raw.voice_activated_corgi);
                mediaPlayer.setLooping(true);
                mediaPlayer.setDisplay(vidHolder);
                mediaPlayer.setOnPreparedListener(this);
                mediaPlayer.prepare();
            }
            catch(Exception e){
                e.printStackTrace();
            }
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
    
        }
    
        @Override
        public void onPrepared(MediaPlayer mp) {
            mediaPlayer.start();
        }
    }
    

    and

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    xmlns:tools="http://schemas.android.com/tools"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="#000000"
                    android:paddingBottom="@dimen/activity_vertical_margin"
                    android:paddingLeft="@dimen/activity_horizontal_margin"
                    android:paddingRight="@dimen/activity_horizontal_margin"
                    android:paddingTop="@dimen/activity_vertical_margin" >
    
        <SurfaceView
            android:id="@+id/surfView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
    
    </RelativeLayout>
    

    Based on the guide at

    http://code.tutsplus.com/tutorials/streaming-video-in-android-apps--cms-19888

    Note: I have a feeling I need to handle the onDreamStarted() and the onPrepared() in a bit smarter fashion. But it works as of now. But if I needed the MediaController, then that'd get a bit more difficult.