4

I have created a custom VideoView class which extends VideoView and declared the three constructors:

package com.tibo.webtv;

import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import org.apache.http.conn.ConnectTimeoutException;
import com.framework.utilityframe.log.log;
import com.framework.utilityframe.utility.utility;
import com.tibo.webtv.activities.PlayerActivity;
import com.tibo.webtv.database.objects.ServerResponseObject;
import com.tibo.webtv.database.objects.TVChannelObject;
import com.tibo.webtv.global.Global;
import com.tibo.webtv.util.TiboCacheKey;
import com.tibo.webtv.util.Util;
import com.tibo.webtv.web.TiboLog;
import com.tibo.webtv.web.WebHelper3;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.AttributeSet;
import android.widget.Toast;
import android.widget.VideoView;

public class CustomVideoView extends VideoView implements OnPreparedListener,OnErrorListener,OnInfoListener,OnCompletionListener
{
    private long buffer_start_time;
    private long buffer_end_time;
    private String token;
    private Handler handler = new Handler();

    public CustomVideoView(Context context) 
    {
        super(context); 
    }
    public CustomVideoView(Context context, AttributeSet attrs) 
    {
        super(context, attrs);
        setOnPreparedListener(this);
        setOnErrorListener(this);
        setOnInfoListener(this);
    }

    public CustomVideoView(Context context, AttributeSet attrs, int defStyle) 
    {
        super(context, attrs, defStyle);
    }

    public TVChannelObject getCurrentPlayingChannel() 
    {
        return current_playing_channel;
    }
    public void setCurrentPlayingChannel(TVChannelObject current_playing_channel) 
    {
        this.current_playing_channel = current_playing_channel;
    }
    public TVChannelObject getPreviousPlayingChannel() 
    {
        return previous_playing_channel;
    }
    public void setPreviousPlayingChannel(TVChannelObject previous_playing_channel)
    {
        this.previous_playing_channel = previous_playing_channel;
    }

    private TVChannelObject current_playing_channel;
    private TVChannelObject previous_playing_channel;
    private String access_way;
    private Date stream_started_time;
    private long stream_play_time;
    private boolean FLAG_STREAM_STARTED;
    private String error_code;



    @Override
    public void stopPlayback()
    {
        new WatchingTime().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        super.stopPlayback();
    }
    @Override
    public void onPrepared(MediaPlayer mp) 
    {
        log.i("on Prepared");
        FLAG_STREAM_STARTED = true;
        stream_started_time = Calendar.getInstance().getTime();
        mp.start();
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) 
    {
        log.i("on onError");
        error_code = what + "";

        Toast.makeText(getContext(),getContext().getString(R.string.videoerror) + " " + error_code, Toast.LENGTH_LONG).show();
        new BlackScreenError().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        if(what == MediaPlayer.MEDIA_ERROR_SERVER_DIED)
            mp.reset();

        else if(what == MediaPlayer.MEDIA_ERROR_UNKNOWN)
            mp.reset();

        return true;
    };

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) 
    {
        log.i("on onInfo");
        if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) 
        {
            buffer_start_time = System.currentTimeMillis();
        }
        else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) 
        {   
            buffer_end_time = System.currentTimeMillis();                           
            new Buffering_Problem().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            FLAG_STREAM_STARTED = false;
        }
        return true;
    }

    @Override
    public void onCompletion(MediaPlayer mp) 
    {
        super.setOnCompletionListener(this);
        new WatchingTime().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public void start(TVChannelObject channel)
    {
        super.start();
        if(current_playing_channel == null)
        {
            current_playing_channel =  channel;
        }
        else
        {
            previous_playing_channel = current_playing_channel;
            current_playing_channel = channel;
            Global.shared_preference.setValue(TiboCacheKey.PLAYING_CHANNEL, current_playing_channel.number);
            Global.shared_preference.setValue(TiboCacheKey.LAST_CHANNEL_VIEWED, previous_playing_channel.number);
        }
        this.access_way = "-1";
    }

    public synchronized void start(TVChannelObject channel,String access_way)
    {
        super.start();

        if(isPlaying())
        {
            this.stopPlayback();
        }
        if(current_playing_channel == null)
        {
            current_playing_channel =  channel;
        }
        else
        {
            previous_playing_channel = current_playing_channel;
            current_playing_channel = channel;

            Global.shared_preference.setValue(TiboCacheKey.PLAYING_CHANNEL, current_playing_channel.number);
            if(!utility.stringCompareIgnoreCase(current_playing_channel.videotype, "2"))
            {
                Global.shared_preference.setValue(TiboCacheKey.LAST_CHANNEL_VIEWED, current_playing_channel.number);
            }
        }
        this.access_way = access_way;

        if (current_playing_channel.token.trim().toLowerCase(Locale.getDefault()).toCharArray()[0] == '1') 
        {
            log.i("Channel with token!!!");
            new PlayStreamWithToken().execute("");
        } 
        else 
        {
            log.i("Channel without token!!!");
            token = "";     
            setVideoURI(Uri.parse(current_playing_channel.url));
            start();
            closePlayerActivityAfterSpecificTime(1000 * 60 * 120);
        }
        new ChannelHits().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    private void closePlayerActivityAfterSpecificTime(int milliseconds) 
    {
        handler.removeCallbacks(ClosePlayerActivity);
        handler.postDelayed(ClosePlayerActivity, milliseconds);
    }

    private Runnable ClosePlayerActivity = new Runnable() {
        public void run() {
            new ClosePlayerActivityAfterInActivity().execute(0);
        }
    };

    private class PlayStreamWithToken extends AsyncTask<String, String, String> 
    {
        ServerResponseObject<String> token_response = null;
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String... params)
        {
            Thread.currentThread().setName("get token");
            log.i("Channel with token!!!");
            log.i("token url",current_playing_channel.TokenUrl);
            try 
            {
                token_response = WebHelper3.getToken(current_playing_channel.TokenUrl);

                if(token_response != null)
                {
                    if(token_response.status_code < 300)
                    {
                        if(!utility.stringCompareIgnoreCase(token_response.extra_data, ""))
                        {
                            token = token_response.extra_data;
                            log.i("token",token);
                            return Util.RESPONSE_OK;
                        }
                    }
                    else
                    {
                        //TODO handle error
                        return Util.RESPONSE_ERROR;
                    }
                }
                else
                {
                    //TODO hanlde
                    token = "";
                    return Util.RESPONSE_NULL;
                }
            } 
            catch (ConnectTimeoutException e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return Util.RESPONSE_TIME_OUT;
            }
            return "";
        }

        protected void onPostExecute(String response) 
        {
            if(utility.stringCompareIgnoreCase(response, Util.RESPONSE_OK))
            {
                String channel_url_to_play = current_playing_channel.url;
                channel_url_to_play += token.trim();
                log.i("url to play with token :", channel_url_to_play);
                setVideoURI(Uri.parse(channel_url_to_play));
                start();
                closePlayerActivityAfterSpecificTime(1000 * 60 * 120);
            }
            else if(utility.stringCompareIgnoreCase(response, Util.RESPONSE_TIME_OUT))
            {
                //TODO handle timout and null
            }
        }
    }
    private class ClosePlayerActivityAfterInActivity extends AsyncTask<Integer, Integer, Integer> 
    {
        @Override
        protected Integer doInBackground(Integer... params) 
        {
            Thread.currentThread().setName("SleepTask");
            return 0;
        }
        @Override
        protected void onPostExecute(Integer result) 
        {           
            if (isPlaying()) 
            {
                stopPlayback();
            }
            PlayerActivity.this_activity.finish();
        }
    }
    private class Buffering_Problem extends AsyncTask<Integer, Integer, Integer> 
    {
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
        }

        @Override
        protected Integer doInBackground(Integer... params)
        {
            Thread.currentThread().setName("Buffering problem Custom VideoView");

            if (FLAG_STREAM_STARTED)
            {
                TiboLog.logBufferingError(TiboLog.LIVE_TV_BUFFER_ERRORS,current_playing_channel.number, buffer_end_time - buffer_start_time, "Warning");
            }
            else
            {
                TiboLog.logBufferingError(TiboLog.LIVE_TV_BUFFER_ERRORS,current_playing_channel.number, buffer_end_time - buffer_start_time, "Error");
            }
            buffer_end_time = 0;
            buffer_start_time = 0;
            return 0;
        }
    }

    private class BlackScreenError extends AsyncTask<Integer, Integer, Integer> 
    {
        @Override
        protected void onPreExecute() 
        {
            super.onPreExecute();
        }

        @Override
        protected Integer doInBackground(Integer... params) 
        {
            Thread.currentThread().setName("Black Screen Error");
            try 
            {
                TiboLog.logSendError(TiboLog.LOGTYPE_ERROR,current_playing_channel.number, "Error Black Screen " + error_code);

            }
            catch (Exception e) 
            {
                e.printStackTrace();
            }
            return 0;
        }
    }

    private class ChannelHits extends AsyncTask<Integer, Integer, Integer> 
    {
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
        }

        @Override
        protected Integer doInBackground(Integer... params)
        {
            Thread.currentThread().setName("Channel Hit log");
            TiboLog.logChannelHit(TiboLog.LIVE_TV_HITS,current_playing_channel.number, access_way, previous_playing_channel.number);
            return 0;
        }
    }

    private class WatchingTime extends AsyncTask<Integer, Integer, Integer> 
    {
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
        }

        @Override
        protected Integer doInBackground(Integer... params)
        {
            Thread.currentThread().setName("Watching Time Log");
            if(stream_started_time != null)
            {
                long stream_ended_time = Calendar.getInstance().getTime().getTime();
                stream_play_time = stream_ended_time - stream_started_time.getTime();

                int playtime_in_seconds = (int) (stream_play_time)/1000;
                log.i("playtime_in_seconds",playtime_in_seconds+"");
                if (playtime_in_seconds >= 15 && playtime_in_seconds < 108000)
                {
                    TiboLog.sendWatchingTime(TiboLog.LIVE_TV_WATCHING_TIME, current_playing_channel.number, playtime_in_seconds + "");
                }
            }
            return 0;
        }
    }

}

The xml file is as follow:

<RelativeLayout
    android:id="@+id/media_player_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <com.tibo.webtv.CustomVideoView    --line 13
        android:id="@+id/surface_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_gravity="center" />
</RelativeLayout>

When i run this apk on android 4.1, the activity crashes and the log message is:

       11-13 11:36:27.962: E/AndroidRuntime(1040): FATAL EXCEPTION: main
11-13 11:36:27.962: E/AndroidRuntime(1040): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tibo.webtv/com.tibo.webtv.activities.PlayerActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class com.webtv.CustomVideoView
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.access$600(ActivityThread.java:130)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.os.Looper.loop(Looper.java:137)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.main(ActivityThread.java:4745)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.reflect.Method.invokeNative(Native Method)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.reflect.Method.invoke(Method.java:511)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at dalvik.system.NativeStart.main(Native Method)
11-13 11:36:27.962: E/AndroidRuntime(1040): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class com.webtv.CustomVideoView
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:698)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:749)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:256)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.Activity.setContentView(Activity.java:1867)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at com.tibo.webtv.activities.PlayerActivity.onCreate(PlayerActivity.java:188)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.Activity.performCreate(Activity.java:5008)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
11-13 11:36:27.962: E/AndroidRuntime(1040):     ... 11 more
11-13 11:36:27.962: E/AndroidRuntime(1040): Caused by: java.lang.ClassNotFoundException: com.webtv.CustomVideoView
11-13 11:36:27.962: E/AndroidRuntime(1040):     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.createView(LayoutInflater.java:552)
11-13 11:36:27.962: E/AndroidRuntime(1040):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
11-13 11:36:27.962: E/AndroidRuntime(1040):     ... 22 more

I guess the problem is with OnInfoListener as when I remove it everything goes fine.

2 Answers2

0

Problem is with package name. Cross check the full qualified class name which you have used in xml with your class definition. In short when you hit ctrl+left mouse key, you should be redirected to class definition.
It should be com.packagename.yourCustomclassName

kiturk3
  • 549
  • 10
  • 30
0

In my case, i have removed the attribute android:background and I didn't get any inflate exceptions from then on.

adi
  • 984
  • 15
  • 33