title: React-Native-Video controls working in iOS but not android? (Laggy state?)
body: <p>I have a React Native project ver .66.4 with React-native-video 5.2.0 and React-native-video-controls 2.8.1</p>
  <p>I have a VideoPlayer component that has custom controls built into the ref. This component works <em>perfectly</em> in iOS, but it doesn't work on Android. The controls don't update when pressed (play doesn't turn into pause) and in fullscreen it seems there's a view or something blocking the buttons.</p>
  <p>My VideoPlayer component:</p>
  <pre><code>import React, { useCallback, useEffect, useRef, useState } from 'react';
  import { VideoProperties } from 'react-native-video';
  import Video from 'react-native-video-controls';
  import { Animated, DeviceEventEmitter, Dimensions, Modal, StyleSheet, Text, View } from 'react-native';
  import { Image } from 'react-native-elements';
  import { colors } from '../styles/colorPalette';
  import { TouchableOpacity } from 'react-native-gesture-handler';
  import { useTheme } from '../contexts/ThemeContext';
  import { ReactNativeProps } from 'react-native-render-html';
  import { useFocusEffect, useIsFocused } from '@react-navigation/native';
  import Orientation from 'react-native-orientation-locker';
  interface VideoPlayerProps extends VideoProperties {
    autoPlay?: boolean
    categoryOverlay?: boolean | string
    disableSeekSkip?: boolean
    ref?: any
  }
  const VideoPlayer = (props: VideoPlayerProps &amp; ReactNativeProps) =&gt; {
    const [vidAspectRatio, setVidAspectRatio] = useState(16 / 9)
    const [isFullscreen, setIsFullscreen] = useState(false)
    const { darkMode, toggleNavBar } = useTheme();
    const [error, setError] = useState(null)
    const videoRef = useRef&lt;Video&gt;(null);
    const progress = useRef&lt;number&gt;(0)
    const dimensions = {
      height: Dimensions.get('screen').height,
      width: Dimensions.get('screen').width
    }
  
    const handleEnterFullscreen = async () =&gt; {
      setIsFullscreen(true)
      toggleNavBar(false)
    }
  
    const handleExitFullscreen = async () =&gt; {
      setIsFullscreen(false)
      toggleNavBar(true)
    }
  
    const styles = StyleSheet.create({
      container: {
        aspectRatio: vidAspectRatio ? vidAspectRatio : 1.75,
        maxHeight: isFullscreen ? dimensions.width : dimensions.height,
        alignItems: 'center',
        justifyContent: 'center',
      },
      containerFSProps: {
        resizeMode: 'contain',
        marginLeft: 'auto',
        marginRight: 'auto',
      },
      controlsImage: {
        resizeMode: 'contain',
        width: '100%',
      },
      modalContainer: {
        flexGrow: 1,
        justifyContent: 'center',
        backgroundColor: '#000',
        resizeMode: 'contain',
      },
      playIcon: {
        color: darkMode ? colors.primary.purple4 : &quot;#fff&quot;,
        fontSize: 30,
        marginHorizontal: 30,
      },
      playIconContainer: {
        flexDirection: 'row',
        justifyContent: 'space-around',
        alignItems: 'center',
        paddingHorizontal: 15,
        paddingVertical: 7.5,
        borderRadius: 10,
      },
      video: {
        position: 'absolute',
        top: 0,
        bottom: 0,
        left: 0,
        right: 0,
      },
      videoButton: {
        height: 60,
        width: 60,
      },
      videoPlayer: {
        position: 'absolute',
        height: '100%',
        width: '100%',
      },
      videoPoster: {
        position: 'absolute',
        top: 0,
        bottom: 0,
        left: 0,
        right: 0,
        resizeMode: 'cover',
      },
      videoWrapper: {
        position: 'absolute',
        width: '100%',
        height: '100%',
      },
      volumeOverlay: {
        position: 'absolute',
        top: 0,
        right: 0,
      },
      categoryOverlay: {
        paddingHorizontal: 10,
        paddingVertical: 5,
        position: 'absolute',
        color: '#fff',
        bottom: 10,
        right: 10,
        backgroundColor: 'rgba(0,0,0, .75)',
        borderRadius: 10,
        textTransform: 'uppercase',
      },
    });
    
    const VideoPlayerElement = useCallback((props: VideoPlayerProps &amp; ReactNativeProps) =&gt; {
      const [duration, setDuration] = useState(null);
      const [lastTouched, setLastTouched] = useState(0)
      const [isPlaying, setIsPlaying] = useState(!props.paused || false);
      const [isSeeking, setIsSeeking] = useState(false)
      const [controlsActive, setControlsActive] = useState(false);
      const { categoryOverlay, disableSeekSkip = false, source } = props;
      const isFocused = useIsFocused();
  
      const handleError = (e: any) =&gt; {
        console.log(&quot;ERROR: &quot;, e)
      }
  
      const handleSeek = (num: number) =&gt; {
        console.log('handleSeek')
        if (!videoRef.current || videoRef.current.state.seeking === true || (Date.now() - lastTouched &lt; 250)) {
          return
        } else {
        videoRef.current.player.ref.seek(Math.max(0, Math.min((videoRef.current.state.currentTime + num), videoRef.current.state.duration)))
        setLastTouched(Date.now())
        }
      }
  
      const handleLoad = (res: any) =&gt; {
        if (progress.current &gt; 0 &amp;&amp; !disableSeekSkip &amp;&amp; (progress.current != res.currentTime)) {
          videoRef.current.player.ref.seek(progress.current, 300)
        }
        // set height and duration
        duration &amp;&amp; setDuration(res.duration ?? null);
        setVidAspectRatio(res.naturalSize ? (res.naturalSize.width / res.naturalSize.height) : (16 / 9));
      }
  
      const handlePause = (res: any) =&gt; {
        // The logic to handle the pause/play logic
        res.playbackRate === 0 ? setIsPlaying(false) : setIsPlaying(true);
      }
  
      const handlePlayPausePress = () =&gt; {
        videoRef.current.state.paused ? videoRef.current.methods.togglePlayPause(true) : videoRef.current.methods.togglePlayPause(false);
      }
  
      const handleProgress = (event: any) =&gt; {
        progress.current = (event.currentTime);
      }
  
      const handleSetControlsActive = (active: boolean) =&gt; {
        setControlsActive(active)
      }
  
      const convertTime = (seconds: number) =&gt; {
        const secsRemaining = Math.floor(seconds % 60);
        return `${Math.floor(seconds / 60)}:${secsRemaining &lt; 10 ? '0' + secsRemaining : secsRemaining}`
      }
  
      const convertTimeV2 = (secs: number) =&gt; {
        var hours   = Math.floor(secs / 3600)
        var minutes = Math.floor(secs / 60) % 60
        var seconds = Math.floor(secs % 60)
  
        return [hours,minutes,seconds]
            .map(v =&gt; v &lt; 10 ? &quot;0&quot; + v : v)
            .filter((v,i) =&gt; v !== &quot;00&quot; || i &gt; 0)
            .join(&quot;:&quot;)
      }
  
      return (
        &lt;Animated.View style={[styles.container, isFullscreen ? styles.containerFSProps : styles.containerProps]}&gt;
          &lt;View style={styles.videoWrapper}&gt;
            &lt;Video
              ref={videoRef}
              source={source}
              showOnStart
              disableBack
              disableFullscreen
              disablePlayPause
              disableSeekbar={disableSeekSkip}
              disableTimer={disableSeekSkip}
              fullscreen={isFullscreen}
              ignoreSilentSwitch=&quot;ignore&quot;
              muted={props.muted || false}
              paused={videoRef.current?.state.paused || props.paused}
              onEnd={() =&gt; { setIsPlaying(false)}}
              onEnterFullscreen={handleEnterFullscreen}
              onExitFullscreen={handleExitFullscreen}
              onLoad={handleLoad}
              onError={handleError}
              onHideControls={() =&gt; handleSetControlsActive(false)}
              onShowControls={() =&gt; handleSetControlsActive(true)}
              onPlaybackRateChange={handlePause}
              onProgress={handleProgress}
              onSeek={() =&gt; console.log('seeking')}
              seekColor=&quot;#a146b7&quot;
              controlTimeout={3000}
              style={{flex: 1, flexGrow: 1}}
              containerStyle={{flex: 1, flexGrow: 1}}
            /&gt;
          &lt;/View&gt;
          {categoryOverlay &amp;&amp; progress.current == 1 &amp;&amp; 
            &lt;View style={styles.categoryOverlay}&gt;
              &lt;Text style={{color: &quot;#fff&quot;, textTransform: 'uppercase'}}&gt;{(typeof categoryOverlay === 'boolean') &amp;&amp; duration ? convertTime(duration) : categoryOverlay}&lt;/Text&gt;
            &lt;/View&gt;
          }
          { (progress.current == 1 &amp;&amp; !isPlaying) &amp;&amp; &lt;View style={styles.videoPoster}&gt;&lt;Image style={{width: '100%', height: '100%', resizeMode: 'contain'}} source={{ uri: `https://home.test.com${props.poster}` }} /&gt;&lt;/View&gt; }
          { (controlsActive || !isPlaying) &amp;&amp; 
          &lt;&gt;
            { (controlsActive || !videoRef.current.state.paused) &amp;&amp; 
                &lt;TouchableOpacity containerStyle={{position: 'absolute', top: 3, right: 0, zIndex: 999}} onPress={isFullscreen ? handleExitFullscreen : handleEnterFullscreen}&gt;
                  &lt;Image style={{ height: 50, width: 60 }} source={isFullscreen ? require('../assets/icons/Miscellaneous/Video_Controls/minimize.png') : require('../assets/icons/Miscellaneous/Video_Controls/fullscreen.png')} /&gt;
                &lt;/TouchableOpacity&gt;
            }
            &lt;View style={styles.playIconContainer}&gt;
              { !disableSeekSkip &amp;&amp; &lt;TouchableOpacity disabled={videoRef.current.state.currentTime == 0 || videoRef.current.state.seeking} onPress={() =&gt; handleSeek(-15)}&gt;
                &lt;Image containerStyle={{height: 60, width: 60}} style={styles.controlsImage} source={require('../assets/icons/Miscellaneous/Video_Controls/back-15s.png')}/&gt;
              &lt;/TouchableOpacity&gt; }
              &lt;TouchableOpacity onPress={handlePlayPausePress}&gt;
                &lt;Image containerStyle={{height: 60, width: 60}} source={!videoRef.current.state.paused ? require('../assets/icons/Miscellaneous/Video_Controls/pause-video-white.png') : require('../assets/icons/Miscellaneous/Video_Controls/play-video-white.png')}/&gt;
              &lt;/TouchableOpacity&gt;
              { !disableSeekSkip &amp;&amp; &lt;TouchableOpacity disabled={videoRef.current.state.currentTime == videoRef.current.state.duration || videoRef.current.state.seeking} onPress={() =&gt; handleSeek(15)}&gt;
                &lt;Image containerStyle={{height: 60, width: 60}} style={styles.controlsImage} source={require('../assets/icons/Miscellaneous/Video_Controls/skip-15s.png')}/&gt;
              &lt;/TouchableOpacity&gt; }
            &lt;/View&gt; 
          &lt;/&gt;}
        &lt;/Animated.View&gt;
      );
    }, [isFullscreen])
  
    useEffect(() =&gt; {
      Orientation.lockToPortrait()
      return () =&gt; {
        toggleNavBar(true)
      }
    }, [])
  
    useEffect(() =&gt; {
      if (error) console.log(&quot;ERROR&quot;, error)
    }, [error])
  
    useEffect(() =&gt; {
      isFullscreen ? Orientation.lockToLandscape() : Orientation.lockToPortrait()
    }, [isFullscreen])
    
    return (
      isFullscreen ? 
      &lt;Modal hardwareAccelerated animationType='fade' visible={isFullscreen} supportedOrientations={['landscape', 'portrait']}&gt;
        &lt;View style={[styles.modalContainer]} &gt;
          &lt;VideoPlayerElement {...props} /&gt;
        &lt;/View&gt;
      &lt;/Modal&gt; 
      : 
      &lt;VideoPlayerElement {...props} /&gt;
    )
  }
  
  export default React.memo(VideoPlayer)
  </code></pre>