/*
 * Copyright (C) 2007 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.
 */
package com.nexstreaming.app.apis;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.nexstreaming.app.dialog.NexContentInfoDialog;
import com.nexstreaming.app.nexplayersample.R;
import com.nexstreaming.app.nxb.info.NxbInfo;
import com.nexstreaming.app.util.NetworkBroadcastReceiver;
import com.nexstreaming.app.util.NetworkUtils;
import com.nexstreaming.app.util.NexFileIO;
import com.nexstreaming.app.util.PlayListUtils;
import com.nexstreaming.app.widget.NexImageButton;
import com.nexstreaming.nexplayerengine.NexABRController;
import com.nexstreaming.nexplayerengine.NexALFactory;
import com.nexstreaming.nexplayerengine.NexContentInformation;
import com.nexstreaming.nexplayerengine.NexEventReceiver;
import com.nexstreaming.nexplayerengine.NexPlayer;
import com.nexstreaming.nexplayerengine.NexPlayer.NexErrorCode;
import com.nexstreaming.nexplayerengine.NexPlayer.NexProperty;
import com.nexstreaming.nexplayerengine.NexVideoRenderer;
import com.nexstreaming.nexplayerengine.NexVideoViewFactory;

import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import com.nexstreaming.nexplayerengine.neximaclient.NexIMAWrapper;
import com.nexstreaming.nexplayerengine.NexLog;
import com.google.ads.interactivemedia.v3.api.AdError;


public class NexVASTSample extends AppCompatActivity implements NetworkBroadcastReceiver.NetworkListener{
    public static final Handler mHandler = new Handler();

    protected Uri mCurrentUri = null;
    protected Toolbar mToolbar;

    private static final String LOG_TAG = "NexVASTSample";

    private final int VIDEO_ONLY = 2;

    private static final int BANDWIDTH_KBPS = 1024;

    private static final int RESET_PLAYER_ALL = 0;
    private static final int RESET_PLAYER_PROGRESS = 1;
    private static final int RESET_PLAYER_BASIC = 2;

    private static final int REPLAY_MODE_NEXT = 0;
    private static final int REPLAY_MODE_AGAIN = 1;
    private static final int REPLAY_MODE_QUIT = 2;
    private static final int REPLAY_MODE_PREVIOUS = 3;

    private static final int SCALE_FIT_TO_SCREEN = 0;
    private static final int SCALE_ORIGINAL = 1;
    private static final int SCALE_STRETCH_TO_SCREEN = 2;

    private int mScaleMode = SCALE_FIT_TO_SCREEN;

    private ArrayList<File> mFileList;
    protected String mCurrentPath;
    private boolean mExistFollowingContentPath;

    private int mCurrentPosition = 0;
    private String mTargetSubtitlePath = null;

    private NexContentInformation mContentInfo = null;
    private ArrayList<NxbInfo>mNxbWholeList;

    //preference
    private boolean mNeedResume = false;
    private boolean mIsHeadsetRemoved = false;

    private NexVideoViewFactory.INexVideoView mVideoView = null;
    protected NexPlayer mNexPlayer;
    private NexEventReceiver mEventReceiver;
    private NexALFactory mNexALFactory;
    private NexABRController mABRController;

    //ui components
    private ViewGroup mVisibilityLayout;
    private ThumbnailSeekBar mSeekBar;
    private NexImageButton mRewindButton;
    private NexImageButton mPlayPauseButton;
    private NexImageButton mFastForwardButton;
    private TextView mErrorView;

    private int mVideoWidth = 0;
    private int mVideoHeight = 0;

    // buffer info
    private RelativeLayout mProgressLayout;
    private TextView mProgressTextView;
    private boolean mIsBuffering = false;

    // seek information
    private int mProgressBase = 0;
    private int mSeekPoint = -1;
    private boolean mIsSeeking = false;

    //Streaming status
    private boolean mIsStreaming = false;
    private boolean mIsLive = false;

    //player status
    private enum PLAYER_FLOW_STATE {
        START_PLAY, BEGINNING_OF_COMPLETE, END_OF_COMPLETE, FINISH_ACTIVITY, BEGINNING_OF_ONERROR, END_OF_ONERROR, STATE_NONE
    };
    private PLAYER_FLOW_STATE mPlayerState = PLAYER_FLOW_STATE.STATE_NONE;

    private boolean mForeground = true;

    private RelativeLayout mParentView;

    private boolean mNeedStartSeekBarTime = false;

    private PlayerSampleUtils playerSampleUtils = PlayerSampleUtils.sharedInstance();
    private PlayListUtils mPlayListUtil;

    private NexPreferenceData mPrefData = null;

    private NexContentInfoDialog mContentInfoDialog = null;

    private Timer mTimer = null;

    private static final int MSG_START_TIME  = 0;
    private static final int MSG_UPDATE_TIME  = 1;

    WaitingForUnlockThread mWaitingThread = null;

    private String mVASTUrl = null;
    private NexIMAWrapper mNexVASTController = null;
    private Button mAdSkipButton = null;
    private CountDownTimer mAdSkipTimer = null;
    private CountDownTimer mAdStatus = null;
    private TextView mAdStatusText = null;

    private boolean mNeedToStart = false;

    private boolean isSeamlessMode = false;

    @SuppressLint("InlinedApi")

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        NexLog.d(LOG_TAG, "onKeyDown keyCode : " + keyCode);
        if (mSeekBar != null && mSeekBar.hasFocus()) {
            if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
                mIsSeeking = (mNexPlayer.seek(mSeekBar.getProgress()) == 0);
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_content_info:
                createAndShowContentInfoDialog();
                break;
            default:
                return false;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.player_activity_action, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public void onNetworkStateChanged(Context context) {
        if( NetworkUtils.getConnectivityStatus(context) != NetworkUtils.TYPE_NOT_CONNECTED ) {
            if( mNexPlayer != null && mNexPlayer.isInitialized() && isStreaming() ) {
                int state = mNexPlayer.getState();

                if( state == NexPlayer.NEXPLAYER_STATE_PLAY || state == NexPlayer.NEXPLAYER_STATE_PAUSE )
                    mNexPlayer.reconnectNetwork();
            }
        }
    }

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        mPrefData = new NexPreferenceData( getApplicationContext() );
        mPrefData.loadPreferenceData();
        setPreloader();
        getIntentExtra();

        if( Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO ) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
        }
        if( Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
        }

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.nexplayer_sample);
        mPlayListUtil = new PlayListUtils(getResources().getStringArray(R.array.playable_extension_list));
        setUIComponents();

        if( setPlayer() < 0 ) {
            mPlayerState = PLAYER_FLOW_STATE.END_OF_ONERROR;
            return;
        }
        mNexVASTController = new NexIMAWrapper(this, (ViewGroup) mVideoView.getView().getParent());
        startPlay();

        SetAdsComponent();
        setAlertDialogBuilder();
    }

    @Override
    protected void onPause() {
        super.onPause();
        NexLog.d(LOG_TAG, "onPause");
        mNeedToStart = true;
        if (mNexVASTController != null) {
            mNexVASTController.pause();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        NexLog.d(LOG_TAG, "onStop");
    }

    @Override
    protected void onResume() {
        super.onResume();
        NexLog.d(LOG_TAG, "onResume");
        if (mNeedToStart) {
            if (mNexVASTController != null) {
                mNexVASTController.resume();
            }
        }
        mNeedToStart = false;
    }

    @Override
    protected void onStart() {
        super.onStart();
        mForeground = true;
    }

    @Override
    protected void onDestroy() {
        stopPlayer();
        releasePlayer();
        mVideoView.release();
        unregisterReceivers();

        if (mCurrentPath != null)
            getContentPath(REPLAY_MODE_QUIT);

        if (mNexVASTController != null)
            mNexVASTController.release();

        PlayerEnginePreLoader.deleteAPKAsset(this);
        super.onDestroy();
    }

    protected boolean isStreaming() {
        return mIsStreaming;
    }

    protected void addEventReceiver() {
        mEventReceiver = new NexEventReceiver() {
            @Override
            public void onAsyncCmdComplete(NexPlayer mp, int command, int result, int param1, int param2) {
                super.onAsyncCmdComplete(mp, command, result, param1, param2);

                NexLog.d(LOG_TAG, "onAsyncCmdComplete : mp : " + mp + " command : " + command + ", result : " + result);
                switch (command) {
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_OPEN_LOCAL:
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_OPEN_STREAMING:
                        NexLog.d(LOG_TAG, "onAsyncCmdComplete : OPEN");
                        clearBufferStatus();
                        mExistFollowingContentPath = false;
                        mPlayerState = PLAYER_FLOW_STATE.BEGINNING_OF_COMPLETE;

                        if(result == 0) {
                            final int duration = mNexPlayer.getContentInfoInt(NexPlayer.CONTENT_INFO_INDEX_MEDIA_DURATION);
                            mContentInfo = mNexPlayer.getContentInfo();
                            if( mContentInfoDialog != null )
                                mContentInfoDialog.setContentInfo(mContentInfo);

                            if ( !TextUtils.isEmpty(mTargetSubtitlePath) ){
                                result = mNexPlayer.changeSubtitlePath(mTargetSubtitlePath);
                                if( result != 0 && result != 1 ) {
                                    showToastMsg(getString(R.string.invalid_subtitle_path));
                                }
                            }

                            if( duration < 0 ) {
                                mIsLive = true;
                            }

                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        if( mCurrentPath != null )
                                            mToolbar.setTitle(NexFileIO.getContentTitle(mCurrentPath));

                                        mSeekBar.setMax(duration);
                                        mSeekBar.setDurationTimeText(duration);

                                        if( mForeground ) {
                                            startPlayer();
                                        }
                                    }
                                    catch (Throwable e) {
                                        NexLog.d(LOG_TAG, "Exception - onAsyncCmdComplete : OPEN : " + e.getMessage() );
                                        e.printStackTrace();
                                    }
                                }
                            });
                        }
                        else {
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if( mCurrentPath != null )
                                        mToolbar.setTitle(NexFileIO.getContentTitle(mCurrentPath));
                                }
                            });
                            onError(mp, NexErrorCode.fromIntegerValue(result));
                        }
                        break;
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_START_LOCAL:
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_START_STREAMING:
                        NexLog.d(LOG_TAG, "onAsyncCmdComplete : START");

                        mPlayerState = PLAYER_FLOW_STATE.BEGINNING_OF_COMPLETE;

                        if(result == 0) {
                            if(mIsStreaming) {
                                NxbInfo info = NxbInfo.getNxbInfo(mNxbWholeList, mCurrentPath, mCurrentPosition);
                                Intent intent = getIntent();
                                ArrayList<String> optionalHeaders = intent.getStringArrayListExtra("WVDRMOptionalHeaders");
                                String optionalStrings = "";
                                if(optionalHeaders != null) {
                                    for (String s : optionalHeaders) {
                                        optionalStrings += (s + "/");
                                    }
                                }

                                if( PlaybackHistory.isExist(NexVASTSample.this, info) ) {
                                    PlaybackHistory.updateHistory(NexVASTSample.this,	info, optionalStrings);
                                } else {
                                    PlaybackHistory.addHistory(NexVASTSample.this, info, optionalStrings);
                                }
                            }

                            mHandler.post(new Runnable() {
                                @SuppressLint("NewApi")
                                @Override
                                public void run() {
                                    mPlayPauseButton.setImageResource(android.R.drawable.ic_media_pause);

                                }
                            });
                        } else {
                            onError(mp, NexErrorCode.fromIntegerValue(result));
                        }

                        if( mPlayerState == PLAYER_FLOW_STATE.BEGINNING_OF_COMPLETE ) {
                            mPlayerState = PLAYER_FLOW_STATE.END_OF_COMPLETE;
                        }
                        break;
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_PAUSE:
                        if( mIsLive && mForeground )
                            scheduleSeekableRangeTimeTask();
                        break;
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_STOP:
                        NexLog.d(LOG_TAG, "onAsyncCmdComplete : STOP");

                        cancelSeekableRangeTimer();
                        postProcessingForStopCmd();

                        break;
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_SET_MEDIA_STREAM:
                        NexLog.d(LOG_TAG, "onAsyncCmdComplete : SET_MEDIA_STREAM. param1 : " + param1 + ", param2  : " + param2);

                        mPlayerState = PLAYER_FLOW_STATE.BEGINNING_OF_COMPLETE;
                        mContentInfo = mNexPlayer.getContentInfo();
                        mNeedResume = false;

                        if(mPlayerState == PLAYER_FLOW_STATE.BEGINNING_OF_COMPLETE)
                            mPlayerState = PLAYER_FLOW_STATE.END_OF_COMPLETE;

                        NexPlayer.NexErrorCode errorCode = NexErrorCode.fromIntegerValue(result);

                        break;
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_SEEK:
                        NexLog.d(LOG_TAG, "onAsyncCmdComplete : SEEK");
                        if( mSeekPoint > -1 ) {
                            if( mForeground )
                                mNexPlayer.seek(mSeekPoint);
                            else
                                mIsSeeking = false;
                            mSeekPoint = -1;
                        } else if( mNexPlayer.getState() == NexPlayer.NEXPLAYER_STATE_PAUSE ) {
                            mSeekBar.setProgress(mNexPlayer.getCurrentPosition());
                            mIsSeeking = false;
                        } else {
                            if( mIsHeadsetRemoved || !mForeground ) {
                                mHandler.post(new Runnable() {

                                    @Override
                                    public void run() {
                                        mNexPlayer.pause();
                                        mPlayPauseButton.setImageResource(android.R.drawable.ic_media_play);
                                        mIsHeadsetRemoved = false;
                                    }
                                });
                            }

                            mIsSeeking = false;
                        }
                        break;
                    case NexPlayer.NEXPLAYER_ASYNC_CMD_RESUME:
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mPlayPauseButton.setImageResource(android.R.drawable.ic_media_pause);
                            }
                        });

                        cancelSeekableRangeTimer();
                        break;
                }
            }

            @Override
            public void onEndOfContent(NexPlayer mp) {
                getContentPath(mPrefData.mReplayMode);

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mNexPlayer.pause();
                    }
                });
            }

            @Override
            public void onTime(NexPlayer mp, int millisec) {
                showProgressBar(millisec);
            }

            @Override
            public void onHTTPResponse(NexPlayer mp, String strResponse) {
                playerSampleUtils.logHTTPResponse(strResponse);
            }

            @Override
            public void onHTTPRequest(NexPlayer mp, String strRequest) {
                playerSampleUtils.logHTTPRequest(strRequest);
            }

            @Override
            public void onError(NexPlayer mp, NexErrorCode errorcode) {
                NexLog.e(LOG_TAG, "onError: " + errorcode);
                if (mPlayerState == PLAYER_FLOW_STATE.BEGINNING_OF_ONERROR)
                    return;

                mPlayerState = PLAYER_FLOW_STATE.BEGINNING_OF_ONERROR;

                String lineBreak = "\n";
                if ("".equals(mp.getDetailedError())) {
                    lineBreak = "";
                }

                if( errorcode == null ) {
                    showErrorStatus("onError : Unknown Error Occured with Invalid errorcode object");
                }
                else {
                    switch (errorcode.getCategory()) {
                        case API:
                        case BASE:
                        case NO_ERROR:
                        case INTERNAL:
                            showErrorStatus("An internal error occurred while attempting to open the media: "
                                    + errorcode.name());
                            break;

                        case AUTH:
                            showErrorStatus("You are not authorized to view this content, "
                                    + "or it was not possible to verify your authorization, "
                                    + "for the following reason:\n\n" + errorcode.getDesc());
                            break;

                        case CONTENT_ERROR:
                            showErrorStatus("The content cannot be played back, probably because of an error in "
                                    + "the format of the content (0x"
                                    + Integer.toHexString(errorcode.getIntegerCode())
                                    + ": " + errorcode.name() + ").");
                            break;

                        case NETWORK:
                            showErrorStatus("The content cannot be played back because of a "
                                    + "problem with the network.  This may be temporary, "
                                    + "and trying again later may resolve the problem.\n("
                                    + errorcode.getDesc() + lineBreak + mp.getDetailedError() + ")");
                            break;

                        case NOT_SUPPORT:
                            showErrorStatus("The content can not be played back because it uses a "
                                    + "feature which is not supported by NexPlayer.\n\n("
                                    + errorcode.getDesc() + ")");
                            break;

                        case GENERAL:
                            showErrorStatus("The content cannot be played back for the following reason:\n\n"
                                    + errorcode.getDesc() + lineBreak + mp.getDetailedError());
                            break;

                        case PROTOCOL:
                            showErrorStatus("The content cannot be played back because of a "
                                    + "protocol error.  This may be due to a problem with "
                                    + "the network or a problem with the server you are "
                                    + "trying to access.  Trying again later may resolve "
                                    + "the problem.\n(" + errorcode.name()  + lineBreak + mp.getDetailedError() + ")");
                            break;
                        case DOWNLOADER:
                            showErrorStatus("Download has the problem\n\n(" + errorcode.name() + ")" );
                            break;

                        case SYSTEM:
                            showErrorStatus("SYSTEM has the problem\n\n(" + errorcode.name() + ")" );
                            break;
                    }
                }

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        int state = mNexPlayer.getState();

                        if ( state == NexPlayer.NEXPLAYER_STATE_PLAY
                                || state == NexPlayer.NEXPLAYER_STATE_PAUSE ) {
                            mNexPlayer.stop();
                        }
                        else if( state == NexPlayer.NEXPLAYER_STATE_STOP ){
                            closePlayer();
                            mPlayerState = PLAYER_FLOW_STATE.END_OF_ONERROR;
                        }
                        else if( state == NexPlayer.NEXPLAYER_STATE_CLOSED ) {
                            mPlayerState = PLAYER_FLOW_STATE.END_OF_ONERROR;
                        }
                    }
                });

                resetPlayerStatus(RESET_PLAYER_PROGRESS);
            }

            @Override
            public void onDataInactivityTimeOut(NexPlayer mp) {
                onError(mp, NexErrorCode.DATA_INACTIVITY_TIMEOUT);
            }

            @Override
            public void onBufferingBegin(NexPlayer mp) {
                mIsBuffering = true;
                showBufferStatus(getResources().getString(R.string.buffer_start));
                enableUIControls(false);
            }

            @Override
            public void onBufferingEnd(NexPlayer mp) {
                mIsBuffering = false;
                clearBufferStatus();
                enableUIControls(true);

                if(mSeekPoint > -1) {
                    if( mForeground )
                        mNexPlayer.seek(mSeekPoint);
                    else
                        mIsSeeking = false;
                    mSeekPoint = -1;
                }
            }

            @Override
            public void onBuffering(NexPlayer mp, int progress_in_percent) {
                showBufferStatus(getResources().getString(R.string.buffer_ing) +
                        progress_in_percent + getResources().getString(R.string.buffer_percent));
            }

            @Override
            public void onAudioRenderCreate(NexPlayer mp, int samplingRate, int channelNum) {
                NexLog.d(LOG_TAG, "onAudioRenderCreate");
            }

            @Override
            public void onVideoRenderCreate(NexPlayer mp, int width, int height,
                                            Object rgbBuffer) {
                NexLog.d(LOG_TAG, "onVideoRenderCreate");
            }

            @Override
            public void onStatusReport(NexPlayer mp, int msg, int param1) {
                NexLog.d(LOG_TAG, "onStatusReport msg : " + msg + " , param1 : " + param1);

                if (msg == NexPlayer.NEXPLAYER_STATUS_REPORT_CONTENT_INFO_UPDATED) {
                    mContentInfo = mNexPlayer.getContentInfo();

                    if( mContentInfoDialog != null )
                        mContentInfoDialog.setContentInfo(mContentInfo);

                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            String text = "Track : " + NexContentInfoExtractor.getCurrTrackID(NexPlayer.MEDIA_STREAM_TYPE_VIDEO, mContentInfo);
                        }
                    });

                    if(!mIsLive) {
                        mHandler.post(new Runnable() {

                            @Override
                            public void run() {
                                if( mContentInfo != null ) {
                                    mSeekBar.setMax(mContentInfo.mMediaDuration);
                                    mSeekBar.setDurationTimeText(mContentInfo.mMediaDuration);
                                }
                            }
                        });
                    }
                }
                else if (msg == NexPlayer.NEXPLAYER_STATUS_REPORT_STREAM_RECV_PAUSE) {
                    NexLog.d(LOG_TAG, "Stream Receive Pause.");
                }
                else if (msg == NexPlayer.NEXPLAYER_STATUS_REPORT_STREAM_RECV_RESUME) {
                    NexLog.d(LOG_TAG, "Stream Receive Resume.");
                }
            }
        };

        mNexPlayer.addEventReceiver(mEventReceiver);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        setIntent(intent);
        getIntentExtra();
        NexLog.d(LOG_TAG, "onNewIntent");

        if(mCurrentPath != null && mNexPlayer != null) {
            int state = mNexPlayer.getState();

            if( state != NexPlayer.NEXPLAYER_STATE_STOP &&
                    state != NexPlayer.NEXPLAYER_STATE_NONE ) {

                resetPlayerStatus(RESET_PLAYER_ALL);

                mExistFollowingContentPath = true;

                if (state == NexPlayer.NEXPLAYER_STATE_CLOSED) {
                    startPlay();
                } else if (state > NexPlayer.NEXPLAYER_STATE_STOP) {
                    stopPlayer();

                }
            }
        }
        super.onNewIntent(intent);
    }

    private void setAlertDialogBuilder() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(getString(R.string.vast_seamless_title));
        builder.setItems(NexAdsMetadata.getNameList(), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                mVASTUrl = NexAdsMetadata.getVASTUrl(which);
                PrepareVAST();
            }
        });
        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                NexLog.d(LOG_TAG, "onCancel");
                finish();
            }
        });
        builder.create().show();
    }

    private void setPreloader() {
        if( !PlayerEnginePreLoader.isLoaded() ) {
            NexLog.d(LOG_TAG, "Load NexPlayerEngine Library");
            int codecMode = mPrefData.mPreloadHWOnly ? 2 : mPrefData.mCodecMode;
            String libraryPath = this.getApplicationInfo().dataDir+"/" ;
            PlayerEnginePreLoader.Load(libraryPath, this, codecMode);
        }
    }


    private void notifyKeyGuardUnlocked() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if ( mPrefData.mHomeButtonMode == NexPreferenceData.HOME_BUTTON_MODE_STOP )
                    startPlayer();
                else {
                    resumePlayer();
                }
            }
        });
    }

    private void resumePlayer() {
        if( mNexPlayer != null && mNexPlayer.getState()==NexPlayer.NEXPLAYER_STATE_PAUSE && !mIsHeadsetRemoved || mNeedResume ) {
            mNexPlayer.resume();
            mNeedResume = false;
        }
    }

    private void startPlayer() {
        if( mNexPlayer != null && mNexPlayer.getState() == NexPlayer.NEXPLAYER_STATE_STOP &&
                mPlayerState != PLAYER_FLOW_STATE.BEGINNING_OF_ONERROR &&
                mPlayerState != PLAYER_FLOW_STATE.END_OF_ONERROR ) {
            int startSec = (mIsLive ? 0: mSeekBar.getProgress());

            if( !mNeedStartSeekBarTime ) {
                startSec = mPrefData.mStartSec * 1000;
            }
            mNeedStartSeekBarTime = false;
            mNexPlayer.start(startSec);
            mSeekBar.setCurrentTimeText(startSec);
        }
    }

    private void resetPlayerStatus(int resetMode) {
        switch (resetMode) {
            case RESET_PLAYER_ALL:
                mVideoWidth = 0;
                mVideoHeight = 0;
                mIsLive = false;
                mContentInfo = null;
                mExistFollowingContentPath = false;

                if (mABRController != null)
                    mABRController.setABREnabled(true);
            case RESET_PLAYER_PROGRESS:
            case RESET_PLAYER_BASIC:
                resetSeekStatus();
                break;
            default:
                break;
        }

        mHandler.post(new Runnable() {
            int mode;

            public Runnable init(int resetMode) {
                this.mode = resetMode;
                return (this);
            }

            @Override
            public void run() {
                switch (mode) {
                    case RESET_PLAYER_ALL:
                        if (mSeekBar != null)
                            mSeekBar.resetSeekBarStatus();
                        if (mErrorView != null) {
                            mErrorView.setVisibility(View.INVISIBLE);
                            mErrorView.requestLayout();
                        }
                    case RESET_PLAYER_PROGRESS:
                        if (mSeekBar != null)
                            mSeekBar.setProgress(0);
                    case RESET_PLAYER_BASIC:
                        if (mPlayPauseButton != null)
                            mPlayPauseButton.setImageResource(android.R.drawable.ic_media_play);
                        break;
                    default:
                        break;
                }
            }
        }.init(resetMode));
    }

    private void closePlayer() {
        mNexPlayer.close();
    }

    private void stopPlayer() {
        if( mNexPlayer.getState() > NexPlayer.NEXPLAYER_STATE_STOP ) {
            mNexPlayer.stop();
            try {
                while(mNexPlayer.getState() !=NexPlayer.NEXPLAYER_STATE_STOP) {
                    Thread.sleep(100);
                }
            }
            catch (InterruptedException e) {
                NexLog.e(LOG_TAG, "Exception - stopPlayer() : " + e.getMessage());
            }
        }
    }

    private void unregisterReceivers() {
        NetworkBroadcastReceiver.removeListener(this);
    }

    private void releasePlayer() {
        try {
            if (mNexPlayer != null) {
                if (mNexPlayer.getState() > NexPlayer.NEXPLAYER_STATE_CLOSED) {
                    closePlayer();
                }
                mNexPlayer.release();
                mNexALFactory.release();
            }
        }
        catch (Exception e) {
            NexLog.e(LOG_TAG, "Exception - releasePlayer() : " + e.getMessage());
        }
    }

    private void getIntentExtra() {
        Intent intent = getIntent();
        Uri uri = intent.getData();

        if(uri != null) {
            mCurrentUri = uri;
            mIsStreaming = false;
            String tmpString;

            String proj[] = { MediaStore.Video.Media._ID,
                    MediaStore.Video.Media.DATA};

            ContentResolver cr = getContentResolver();
            Cursor videoCursor = null;
            try {
                videoCursor = cr.query(uri, proj, null, null, null);
            }
            catch(Exception e) {
                NexLog.e(LOG_TAG, "Exception - getIntentExtra() : " + e.getMessage());
            }

            if (videoCursor != null && videoCursor.moveToFirst()) {
                int videoDataCol = videoCursor
                        .getColumnIndex(MediaStore.Video.Media.DATA);
                String url = videoCursor.getString(videoDataCol);

                if (url != null && url.length() > 0) {
                    mCurrentPath = url;
                }

                videoCursor.close();
            }
            else {
                tmpString = Uri.decode(uri.toString());

                if (tmpString.startsWith("http://")
                        || tmpString.startsWith("https://")
                        || tmpString.startsWith("rtsp://")
                        || tmpString.startsWith("mms://")) {
                    mIsStreaming = true;
                    mCurrentPath = tmpString;
                } else if (tmpString.startsWith("file://")) {
                    String path = tmpString.replaceFirst("file://", "");
                    mCurrentPath = path;
                    mTargetSubtitlePath = NexFileIO.subtitlePathFromMediaPath(mCurrentPath);
                }
            }

        } else {
            mFileList = (ArrayList<File>) intent.getSerializableExtra("data");
            mNxbWholeList = (ArrayList<NxbInfo>) intent.getSerializableExtra("wholelist");

            mCurrentPosition = intent.getIntExtra("selectedItem", 0);

            if (mFileList != null) {
                mIsStreaming = false;
                mCurrentPath = mFileList.get(mCurrentPosition).getAbsolutePath();
                mTargetSubtitlePath = NexFileIO.subtitlePathFromMediaPath(mCurrentPath);
            } else {
                mIsStreaming = true;
                mCurrentPath = intent.getStringExtra("theSimpleUrl");
                if (mCurrentPath != null) {
                    mCurrentPath = mCurrentPath.trim();
                }
            }
        }
    }

    private void setUIComponents() {
        setVisibilityLayout();
        setVideoRendererView();
        setSeekLayout();
        setErrorView();
        setControlButton();
        setBufferComponent();
        setupToolbar();
    }

    private void setupToolbar() {
        mToolbar = (Toolbar)findViewById(R.id.tool_bar);
        mToolbar.setTitle("");
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    private void setBufferComponent() {
        mProgressLayout = (RelativeLayout)findViewById(R.id.progress_layout);
        mProgressTextView = (TextView)findViewById(R.id.progress_text);
    }

    @SuppressLint("NewApi")
    private void setVideoRendererView() {
        {
            mVideoView = (NexVideoRenderer) findViewById(R.id.videoview);
            boolean useSurfaceTexture = mPrefData.mUseSurfaceTextrue;
            boolean useRenderThreadWithSurfaceTexture = mPrefData.mUseRenderThread;
            ((NexVideoRenderer) mVideoView).setUseSurfaceTexture(useSurfaceTexture, useRenderThreadWithSurfaceTexture);
        }

        mVideoView.setVisibility(View.VISIBLE);
        if(mPrefData.mColorSpace == 1)
            mVideoView.setScreenPixelFormat(PixelFormat.RGB_565);
        else
            mVideoView.setScreenPixelFormat(PixelFormat.RGBA_8888);

        mVideoView.setListener(new NexVideoRenderer.IListener()
        {

            @Override
            public void onVideoSizeChanged()
            {
                Point videoSize = new Point();
                mVideoView.getVideoSize(videoSize);

                mVideoWidth = videoSize.x;
                mVideoHeight = videoSize.y;

                if (null != mContentInfo) {
                    if (90 == mContentInfo.mRotationDegree || 270 == mContentInfo.mRotationDegree) {
                        int rotationWidth = mVideoWidth;
                        mVideoWidth = mVideoHeight;
                        mVideoHeight = rotationWidth;
                    }
                }

                setPlayerOutputPosition(mVideoWidth, mVideoHeight, mScaleMode);
            }

            @Override
            public void onSizeChanged()
            {
                setPlayerOutputPosition(mVideoWidth, mVideoHeight, mScaleMode);
            }

            @Override
            public void onFirstVideoRenderCreate()
            {
                /* Initialization of mScaleMode has been done at the Activity Instance Initialization
                 * Not every time a new playback begins: NPDS-2404
                 */
                setPlayerOutputPosition(mVideoWidth, mVideoHeight, mScaleMode);
            }

            @Override
            public void onDisplayedRectChanged()
            {
            }
        });
        mVideoView.setPostNexPlayerVideoRendererListener(mEventReceiver);
    }

    private OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            setControllerVisibility(mVisibilityLayout.getVisibility() == View.VISIBLE ? View.INVISIBLE : View.VISIBLE);
        }
    };

    private void setVisibilityLayout() {
        mVisibilityLayout = (ViewGroup)findViewById(R.id.visibility_layout);
        mParentView = (RelativeLayout)findViewById(R.id.parent_view);
        mParentView.setOnClickListener(mOnClickListener);
        mParentView.setBackgroundColor(Color.BLACK);
    }

    private void setControllerVisibility(final int visibility) {
        mHandler.post(new Runnable() {

            @Override
            public void run() {
                mVisibilityLayout.setVisibility(visibility);
                mVisibilityLayout.requestLayout();
                ActionBar toolbar = getSupportActionBar();
                if( toolbar != null ) {
                    if (visibility == View.VISIBLE && !toolbar.isShowing()) {
                        toolbar.show();
                    } else if (visibility == View.INVISIBLE && toolbar.isShowing()) {
                        toolbar.hide();
                    }
                }
            }
        });
    }

    private void createAndShowContentInfoDialog() {
        if( mContentInfo != null ) {
            if( mContentInfoDialog == null )
                mContentInfoDialog = new NexContentInfoDialog(this);

            mContentInfoDialog.setContentInfo(mContentInfo);
            mContentInfoDialog.show();
        }
    }

    private void setSeekLayout() {
        mSeekBar = (ThumbnailSeekBar)findViewById(R.id.seek_layout);
        mSeekBar.setOnSeekBarChangeListener(new ThumbnailSeekBar.ISeekBarListener() {

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                if (mNexPlayer != null && mForeground) {
                    int state = mNexPlayer.getState();

                    if (state > NexPlayer.NEXPLAYER_STATE_STOP) {
                        int position = seekBar.getProgress();

                        boolean shouldSeek = true;
                        if (mIsLive) {
                            long[] seekableRange = mNexPlayer.getSeekableRangeInfo();
                            if (seekableRange != null) {
                                position += (int) seekableRange[0];
                                position = Math.min(position, (int) seekableRange[1]);
                            } else {
                                shouldSeek = false;
                            }
                        }

                        if (shouldSeek) {
                            if (mIsBuffering || mIsSeeking) {
                                mSeekPoint = position;
                                return;
                            }

                            mIsSeeking = (mNexPlayer.seek(position) == 0);
                        }
                    } else if (mNexPlayer != null && mPlayerState == PLAYER_FLOW_STATE.END_OF_ONERROR) {
                        mNeedStartSeekBarTime = true;
                    }
                }
            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress) {
                if (mIsLive) {
                    progress += mProgressBase;
                }
                NexLog.i(LOG_TAG,"Current Progress " + progress);
                mSeekBar.setCurrentTimeText(progress);
            }
        });
    }

    private void setErrorView() {
        mErrorView = (TextView)findViewById(R.id.error_textview);
        mErrorView.setVisibility(View.INVISIBLE);
    }

    private void setControlButton() {
        setupRewindButton();
        setupPlayPauseButton();
        setupFastForwardButton();
    }

    private void setupRewindButton() {
        mRewindButton = (NexImageButton)findViewById(R.id.rewind_button);
        mRewindButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                rewind();
            }
        });
    }

    private void rewind() {
        if( mNexPlayer != null && mNexPlayer.isInitialized()
                && (mNexPlayer.getState() > NexPlayer.NEXPLAYER_STATE_STOP) && mForeground) {
            int seekPosition = mSeekBar.getProgress() - (mPrefData.mSeekOffset * 1000);
            int min = 0;
            if( mSeekPoint >= 0 ) {
                seekPosition = mSeekPoint - (mPrefData.mSeekOffset * 1000);
            }

            if( mIsLive ) {
                long[] seekableRange = mNexPlayer.getSeekableRangeInfo();
                if( seekableRange != null ) {
                    seekPosition += seekableRange[0];
                    min = (int)seekableRange[0];
                }
            }

            seekPosition = Math.max(min, seekPosition);

            if( mIsBuffering || mIsSeeking ) {
                mSeekPoint = seekPosition;
                return;
            }

            mIsSeeking = (mNexPlayer.seek(seekPosition) == 0);
        }
    }

    private void setupFastForwardButton() {
        mFastForwardButton = (NexImageButton)findViewById(R.id.fastforward_button);
        mFastForwardButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                fastForward();
            }
        });
    }

    private void fastForward() {
        if(mNexPlayer != null && mNexPlayer.isInitialized()
                && (mNexPlayer.getState() > NexPlayer.NEXPLAYER_STATE_STOP) && mForeground) {
            int position;
            int duration = mNexPlayer.getContentInfoInt(NexPlayer.CONTENT_INFO_INDEX_MEDIA_DURATION);

            if(mSeekPoint > -1) {
                position = mSeekPoint + (mPrefData.mSeekOffset * 1000);
            }
            else {
                position = mSeekBar.getProgress() + (mPrefData.mSeekOffset * 1000);
            }

            boolean shouldSeek = true;
            if ( mIsLive ) {
                long[] seekableRange = mNexPlayer.getSeekableRangeInfo();
                if ( seekableRange != null ) {
                    position += (int)seekableRange[0];
                    position = Math.min(position, (int)seekableRange[1]);
                } else {
                    shouldSeek = false;
                }
            } else {
                position = Math.min(position, duration);
            }

            if( shouldSeek ) {
                if ( mIsBuffering || mIsSeeking ) {
                    mSeekPoint = position;
                    return;
                }

                mIsSeeking = (mNexPlayer.seek(position) == 0);
            }
        }
    }

    private void setupPlayPauseButton() {
        mPlayPauseButton = (NexImageButton)findViewById(R.id.play_pause_button);
        mPlayPauseButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mPlayerState != PLAYER_FLOW_STATE.END_OF_COMPLETE &&
                        mPlayerState != PLAYER_FLOW_STATE.END_OF_ONERROR) {
                    return;
                }

                if(mNexPlayer != null && mNexPlayer.isInitialized()) {
                    int state = mNexPlayer.getState();

                    if( state == NexPlayer.NEXPLAYER_STATE_PLAY ) {
                        int ret = mNexPlayer.pause();
                        mPlayPauseButton.setImageResource(android.R.drawable.ic_media_play);
                    }
                    else if( state == NexPlayer.NEXPLAYER_STATE_PAUSE ) {
                        int ret = mNexPlayer.resume();
                        mPlayPauseButton.setImageResource(android.R.drawable.ic_media_pause);
                    }
                    else if( state == NexPlayer.NEXPLAYER_STATE_CLOSED ) {
                        mErrorView.setVisibility(View.INVISIBLE);
                        mErrorView.requestLayout();
                        startPlay();
                    }
                    else if( state == NexPlayer.NEXPLAYER_STATE_STOP ) {
                        startPlayer();
                    }
                }
            }
        });
    }

    @SuppressLint("NewApi")
    private int setPlayer() {
        mNexPlayer = new NexPlayer();
        mNexALFactory = new NexALFactory();
        System.gc();

        int debugLogLevel = mPrefData.mLogLevel;

        if( debugLogLevel< 0 )
            debugLogLevel = 0xF0000000;

        if(mNexALFactory.init(this, android.os.Build.MODEL, mPrefData.mRenderMode,debugLogLevel, 1) == false) {
            showErrorStatus("ALFactory initialization failed");
            return -2;
        }

        mNexPlayer.setLicenseFile("/sdcard/test_lic.xml");

        mNexPlayer.setNexALFactory(mNexALFactory);
        if(mNexPlayer.init(this, mPrefData.mLogLevel) != NexErrorCode.NONE) {
            showErrorStatus("NexPlayer initialization failed");
            return -3;
        }

        setProperties();

        addEventReceiver();

        mABRController = new NexABRController(mNexPlayer);
        mABRController.setIABREventListener(new NexABRController.IABREventListener() {
            @Override
            public void onMinMaxBandWidthChanged(NexErrorCode result, int minBwBps, int maxBwBps) {
                if( result == NexErrorCode.NONE ) {
                    mPrefData.setMinMaxBandwidth(minBwBps/BANDWIDTH_KBPS, maxBwBps/BANDWIDTH_KBPS);
                }
                NexLog.d(LOG_TAG,"onMinMaxBandWidthChanged (Result : " + result +", Min : " + minBwBps + ",  Max : " + maxBwBps + ")");
            }

            @Override
            public void onTargetBandWidthChanged(NexErrorCode result, int reqBwBps, int selBwBps) {
            }
        });

        mVideoView.init(mNexPlayer);
        mVideoView.setVisibility(View.VISIBLE);

        return 0;
    }

    private void setProperties() {
        mNexPlayer.setProperty(NexPlayer.NexProperty.MAX_BW, mPrefData.mMaxBandWidth * BANDWIDTH_KBPS);
        mNexPlayer.setProperty(NexPlayer.NexProperty.MIN_BW, mPrefData.mMinBandWidth * BANDWIDTH_KBPS);
        mNexPlayer.setProperty(NexProperty.TIMESTAMP_DIFFERENCE_VDISP_WAIT, mPrefData.mVideoDisplayWait);
        mNexPlayer.setProperty(NexProperty.TIMESTAMP_DIFFERENCE_VDISP_SKIP, mPrefData.mVideoDisplaySkip);
        mNexPlayer.setProperty(NexProperty.AV_SYNC_OFFSET, (int) (mPrefData.mAVSyncOffset * 1000));
        mNexPlayer.setProperty(NexProperty.PREFER_LANGUAGE_AUDIO, mPrefData.mPrefLanguageAudio);
        mNexPlayer.setProperty(NexProperty.PREFER_LANGUAGE_TEXT, mPrefData.mPrefLanguageText);
        mNexPlayer.setProperty(NexProperty.PREFER_BANDWIDTH, 100);
        mNexPlayer.setProperty(NexProperty.PREFER_AV, 1);
        mNexPlayer.setProperty(NexProperty.START_NEARESTBW, mPrefData.mStartNearestBW);
        mNexPlayer.setProperty(NexProperty.SUBTITLE_TEMP_PATH, mPrefData.mSubtitleDownloadPath);
        mNexPlayer.setProperty(NexProperty.ENABLE_CEA708, 1);
        mNexPlayer.setProperty(NexProperty.ENABLE_ID3_TTML, mPrefData.mEnableID3TTML ? 1 : 0);


        mNexPlayer.setDebugLogs( mPrefData.mCodecLogLevel, mPrefData.mRendererLogLevel, mPrefData.mProtoclLogLevel );

        if( !mPrefData.mEnableAudioOnlyTrack )
            mNexPlayer.setProperty(NexProperty.ENABLE_AUDIOONLY_TRACK, 0);

        if( mPrefData.mIgnoreTextmode )
            mNexPlayer.setProperty(NexProperty.IGNORE_CEA608_TEXTMODE_COMMAND, 1);

        if( mPrefData.mEnableWebVTT == false )
            mNexPlayer.setProperty(NexProperty.ENABLE_WEBVTT, 0);

        if( mPrefData.mWebVTTWaitOpen == false )
            mNexPlayer.setProperty(NexProperty.CAPTION_WAITOPEN, 0);

        if( mPrefData.mHLSRunModeStable == true )
            mNexPlayer.setProperty(NexProperty.HLS_RUNMODE, 1);

        if ( mPrefData.mUseEyePleaser == false )
            mNexPlayer.setProperty(NexProperty.SUPPORT_EYE_PLEASER, 0);

        if( mPrefData.mBufferTime != 0 ) {
            mNexPlayer.setProperty(NexProperty.INITIAL_BUFFERING_DURATION, (int) (mPrefData.mBufferTime * 1000));
            mNexPlayer.setProperty(NexProperty.RE_BUFFERING_DURATION, (int) (mPrefData.mBufferTime * 1000));
        }
    }

    private void showToastMsg(final String msg) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private NexPlayerSampleExtensionLoader.ISampleExtension mSampleExtension = null;
    private synchronized NexPlayerSampleExtensionLoader.ISampleExtension getSampleExtension() {
        if ( mSampleExtension == null ) {
            Context context = NexVASTSample.this.getApplicationContext();
            mSampleExtension = NexPlayerSampleExtensionLoader.loadExtension(mNexPlayer, context);
            mSampleExtension.setListener(new NexPlayerSampleExtensionLoader.ISampleExtensionListener() {
                public void errorStatus(NexErrorCode errorCode, String message) {
                    showErrorStatus(message + '(' + errorCode.getDesc() +')');
                }
            });
        }
        return mSampleExtension;
    }

    private void startPlay() {
        if (mNexPlayer.getState() == NexPlayer.NEXPLAYER_STATE_STOP || mPlayerState == PLAYER_FLOW_STATE.START_PLAY )
        {
            closePlayer();
        }
        mCurrentPath = String.valueOf(mCurrentPath);

        mPlayerState = PLAYER_FLOW_STATE.START_PLAY;

        if ( mCurrentPath.length() == 0 ) {
            showErrorStatus("Media URL/path not set for playback");
            return;
        }
        showBufferStatus(getResources().getString(R.string.buffer_open));

        int sourceType = NexPlayer.NEXPLAYER_SOURCE_TYPE_LOCAL_NORMAL;

        if( mIsStreaming ) {
            sourceType = NexPlayer.NEXPLAYER_SOURCE_TYPE_STREAMING;
        }

        int result = mNexPlayer.open(mCurrentPath, null, null, sourceType,
                mPrefData.mUseUDP ? NexPlayer.NEXPLAYER_TRANSPORT_TYPE_UDP :
                        NexPlayer.NEXPLAYER_TRANSPORT_TYPE_TCP);
        if( result != 0 ) {
            mEventReceiver.onError(mNexPlayer, NexErrorCode.fromIntegerValue(result));
        }
    }

    private void showProgressBar(int millisec) {
        if( mSeekBar != null && !mSeekBar.hasFocus() ) {
            if( mIsLive ) {
                long[] seekableRange = mNexPlayer.getSeekableRangeInfo();

                if( seekableRange == null ) {
                    mSeekBar.enableSeekBar(false);
                    mProgressBase = 0;
                } else {
                    mSeekBar.enableSeekBar(true);
                    mProgressBase = (int)seekableRange[0];
                    int seekbarMaxLength = (int)seekableRange[1] - mProgressBase;
                    mSeekBar.setMax(seekbarMaxLength);

                    if(!mSeekBar.isTrackingTouch()) {
                        millisec = Math.min(millisec, (int)seekableRange[1]);
                        int progress = Math.max((millisec - mProgressBase), 0);
                        mSeekBar.setProgress(progress);
                        mSeekBar.setDurationTimeText((int)seekableRange[1]);

                        if( mContentInfo != null ) {
                            int streamType = mContentInfo.mMediaType == VIDEO_ONLY ? NexPlayer.MEDIA_STREAM_TYPE_VIDEO : NexPlayer.MEDIA_STREAM_TYPE_AUDIO;
                            mSeekBar.setSecondaryProgress(mNexPlayer.getBufferInfo(streamType, NexPlayer.NEXPLAYER_BUFINFO_INDEX_LASTCTS));
                        }
                    }
                }
            } else {
                int duration = mNexPlayer.getContentInfoInt(NexPlayer.CONTENT_INFO_INDEX_MEDIA_DURATION);

                if(duration < millisec) {
                    duration = millisec;
                }

                mSeekBar.setMax(duration);

                if(!mSeekBar.isTrackingTouch()) {
                    if(mSeekPoint < 0) {
                        mSeekBar.setProgress(millisec);
                    } else {
                        mSeekBar.setProgress(mSeekPoint);
                    }
                }
            }
        }
        if (mSeekBar != null)
            mSeekBar.setKeyProgressIncrement(mPrefData.mSeekOffset * 1000);

        NexPlayer.PROGRAM_TIME pTime = new NexPlayer.PROGRAM_TIME();
        if (mNexPlayer != null)
            mNexPlayer.getProgramTime(pTime);
    }

    private void showErrorStatus(final String status) {
        mHandler.post(new Runnable() {

            @Override
            public void run() {
                if (mErrorView != null) {
                    mErrorView.setText(status);
                    mErrorView.setVisibility(View.VISIBLE);
                    clearBufferStatus();
                }
            }
        });
    }

    private void resetSeekStatus() {
        mIsBuffering = false;
        mIsSeeking = false;
        mSeekPoint = -1;
        mProgressBase = 0;
    }

    private void scheduleSeekableRangeTimeTask() {
        mTimer = new Timer();
        UpdateSeekableRangeTimerTask timerTask = new UpdateSeekableRangeTimerTask();
        mTimer.schedule(timerTask, 1000, 1000);
    }

    private void cancelSeekableRangeTimer() {
        if( mTimer != null ) {
            mTimer.cancel();
            mTimer = null;
        }
    }

    private class UpdateSeekableRangeTimerTask extends TimerTask {
        @Override
        public void run() {
            NexLog.d(LOG_TAG, "updateSeekableRangeTimer run");
            showProgressBar(mNexPlayer.getCurrentPosition());
        }
    }

    private void getContentPath(int mode) {
        int newIndex = mCurrentPosition;

        switch(mode) {
            case REPLAY_MODE_NEXT:
                newIndex++;
                if( mFileList != null ) {
                    mIsStreaming = false;

                    newIndex = mPlayListUtil.getNextContentIndex(mFileList, newIndex);
                    if( newIndex != PlayListUtils.NOT_FOUND ) {
                        mCurrentPosition = newIndex;
                        mCurrentPath = mFileList.get(mCurrentPosition).getAbsolutePath();
                        mTargetSubtitlePath = NexFileIO.subtitlePathFromMediaPath(mCurrentPath);
                    }
                } else {
                    if( mNxbWholeList != null ) {
                        mIsStreaming = true;

                        if( mNxbWholeList.size() <= newIndex )
                            newIndex = 0;
                        mCurrentPosition = newIndex;
                        NxbInfo info = mNxbWholeList.get(mCurrentPosition);
                        mCurrentPath = info.getUrl();
                    }
                }
                mExistFollowingContentPath = true;
                break;
            case REPLAY_MODE_QUIT:
                mCurrentPath = null;
                break;
            case REPLAY_MODE_AGAIN:
                mExistFollowingContentPath = true;
                break;
            case REPLAY_MODE_PREVIOUS:
                newIndex--;

                if( mFileList != null ) {
                    mIsStreaming = false;

                    newIndex = mPlayListUtil.getPreviousContentIndex(mFileList, newIndex);
                    if( newIndex != PlayListUtils.NOT_FOUND ) {
                        mCurrentPosition = newIndex;
                        mCurrentPath = mFileList.get(mCurrentPosition).getAbsolutePath();
                        mTargetSubtitlePath = NexFileIO.subtitlePathFromMediaPath(mCurrentPath);
                    }
                } else if( mNxbWholeList != null ) {
                    mIsStreaming = true;

                    if( newIndex == -1 )
                        newIndex = mNxbWholeList.size() - 1;
                    mCurrentPosition = newIndex;
                    NxbInfo info = mNxbWholeList.get(mCurrentPosition);
                    mCurrentPath = info.getUrl();
                }
                mExistFollowingContentPath = true;
                break;
        }
    }

    private void enableUIControls(final boolean isEnable){
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if(mPlayPauseButton != null) {
                    mPlayPauseButton.setEnabled(isEnable);
                }
            }
        });
    }

    private void showBufferStatus(final String message){
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mProgressLayout != null) {
                    mProgressLayout.setVisibility(View.VISIBLE);
                    mProgressLayout.requestLayout();
                }

                if (mProgressTextView != null)
                    mProgressTextView.setText(message);
            }
        });
    }
    private void clearBufferStatus(){
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mProgressLayout != null) {
                    mProgressLayout.setVisibility(View.GONE);
                    mProgressLayout.requestLayout();
                }
            }
        });
    }

    @SuppressLint("NewApi")
    private void setPlayerOutputPosition(int videoWidth, int videoHeight, int scaleMode) {
        int width, height, top, left;
        width = height = top = left = 0;
        final int screenWidth = mVideoView.getWidth();
        final int screenHeight = mVideoView.getHeight();
        NexLog.d(LOG_TAG, "setPlayerOutputPosition screenWidth : " + screenWidth + " screenHeight : " + screenHeight);
        if (mVideoWidth == 0 && mVideoHeight == 0)
            scaleMode = SCALE_STRETCH_TO_SCREEN;

        float scale = 1f;

        switch (scaleMode) {
            case SCALE_FIT_TO_SCREEN:
                scale = Math.min((float) screenWidth / (float) videoWidth,
                        (float) screenHeight / (float) videoHeight);

                width = (int) (videoWidth * scale);
                height = (int) (videoHeight * scale);
                top = (screenHeight - height) / 2;
                left = (screenWidth - width) / 2;

                break;
            case SCALE_ORIGINAL:
                width = videoWidth;
                height = videoHeight;
                top = (screenHeight - videoHeight) / 2;
                left = (screenWidth - videoWidth) / 2;

                break;
            case SCALE_STRETCH_TO_SCREEN:
                width = screenWidth;
                height = screenHeight;

                break;
        }

        if (mContentInfo != null && mContentInfo.mCurrVideoStreamID != NexPlayer.MEDIA_STREAM_DISABLE_ID) {
            mVideoView.setOutputPos(left, top, width, height);
        }
    }

    private void postProcessingForStopCmd() {
        NexLog.d(LOG_TAG, "postProcessingForStopCmd mCurrentPath : " + mCurrentPath + " mForeground : " + mForeground);

        // stopped by onError
        if (mPlayerState == PLAYER_FLOW_STATE.BEGINNING_OF_ONERROR)
        {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    closePlayer();
                    mPlayerState = PLAYER_FLOW_STATE.END_OF_ONERROR;
                }
            });
        }
        else
        {
            if ( null == mCurrentPath ) {
                /*
                 * Playback has been completed, no next content to play. Finishing the activity.
                 * onDestroy() will take care of close()/release() of mNexPlayer and mNexALFactory
                 */
                NexLog.d(LOG_TAG, "null == mCurrentPath");
                mPlayerState = PLAYER_FLOW_STATE.FINISH_ACTIVITY;
                finish();
            } else if(mExistFollowingContentPath) {
                // stopped by previous/next button
                System.gc();
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        startPlay();
                    }
                }, 300);
            }
        }
    }

    private class WaitingForUnlockThread extends Thread {
        @Override
        public void run() {
            KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
            if (keyguardManager != null) {
                NexLog.d(LOG_TAG, "waitForKeyGuardUnlock keyguardManager.inKeyguardRestrictedInputMode() : " + keyguardManager.inKeyguardRestrictedInputMode());
                while( keyguardManager.inKeyguardRestrictedInputMode() ) {
                    try {
                        if( isInterrupted() )
                            break;

                        NexLog.d(LOG_TAG, "waiting for 100 msec...");
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            }

            notifyKeyGuardUnlocked();
        }
    }

    private  void PrepareVAST() {
        mNexVASTController.prepareVAST(mVASTUrl);
    }

    private void SetAdsComponent(){

        mNexVASTController.setAdsReadyListener( new NexIMAWrapper.AdsReadyListener() {
            @Override
            public void onAdsLoaded() {
                mNexVASTController.play(0);
            }
            @Override
            public void onAdsLoadError(AdError error) {
                NexLog.i(LOG_TAG, "Ads error : " + error.getMessage());
                stopPlayer();
                showErrorStatus(error.getMessage());
            }
        });
        mNexVASTController.setAdsContentEventListener(new NexIMAWrapper.AdsMediaEventListener() {
            @Override
            public void onAllCompletion(NexPlayer mp) {
                NexLog.i(LOG_TAG, "onADEvent : All Completed");
            }

            @Override
            public void onContentPauseRequested() {
                NexLog.i(LOG_TAG, "onADEvent : Content Pause Requested");
            }

            @Override
            public void onContentResumeRequested() {
                NexLog.i(LOG_TAG, "onADEvent : Content Resume Requested.");
                if (mAdSkipButton != null) {
                    mAdSkipButton.setEnabled(false);
                    mAdSkipButton.setVisibility(View.INVISIBLE);
                }

                if (mAdStatusText != null)
                    mAdStatusText.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onAdLoaded(boolean isLinear, int adPosition, int adCountInGroup, double adDuration, int adGroupidx) {
                NexLog.i(LOG_TAG, "onADEvent : Loaded. isLinear(" + isLinear + ")");
                NexLog.d(LOG_TAG, "Loaded ad " + adPosition + " of " + adCountInGroup + " in ad group "
                        + adGroupidx + " ad Duration : " + adDuration);
            }

            @Override
            public void onAdCompleted() {
                NexLog.i(LOG_TAG, "onADEvent : Completed");
            }

            @Override
            public void onAdStarted(boolean isSkippable, double skipTimeOffset){
                NexLog.i(LOG_TAG, "onAdEvent : Started");
            }

        });
        mNexVASTController.setNexPlayerErrorListener(new NexIMAWrapper.OnErrorListener() {
            @Override
            public void onError(NexPlayer mp, NexPlayer.NexErrorCode errorCode) {
                String errString = "";
                if (errorCode != null) {
                    errString = errorCode.getCategory() + " : " + errorCode.getDesc();
                }
                NexLog.e(LOG_TAG, "onError content: " + errString);
            }
        });
        mNexVASTController.setAdPointsListener(new NexIMAWrapper.AdPointsListener() {
            @Override
            public void onAdPointsLoaded(int[] adPoints) {
                // Set Markers to seekbar, if you use mediacontroller instead of seekbar then use method MediaController.setMarkers(adPoints)
                //Below this line, guided set markers using ThumbnailSeekbar
                if (mSeekBar != null)
                    mSeekBar.setMarkers(adPoints);
            }
            @Override
            public void onAdUrlLoaded(int startTime, String adUrl){
            }
        });
        mNexVASTController.setContentPlayer(mNexPlayer);
    }
}
