<commit_before>package com.tokbox.cordova;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.opentok.android.Connection;
import com.opentok.android.OpentokError;
import com.opentok.android.Publisher;
import com.opentok.android.PublisherKit;
import com.opentok.android.Session;
import com.opentok.android.Stream;
import com.opentok.android.Subscriber;
import com.opentok.android.SubscriberKit;


public class OpenTokAndroidPlugin extends CordovaPlugin implements 
  Session.SessionListener, Session.ConnectionListener, Session.SignalListener, 
  Session.PublisherListener, Session.StreamPropertiesListener{
  
  private String sessionId;
  protected Session mSession;
  public static final String TAG = "OTPlugin";
  public boolean sessionConnected;
  public boolean publishCalled; // we need this because creating publisher before sessionConnected = crash
  public RunnablePublisher myPublisher;
  public HashMap<String, CallbackContext> myEventListeners;
  public HashMap<String, Connection> connectionCollection;
  public HashMap<String, Stream> streamCollection;
  public HashMap<String, RunnableSubscriber> subscriberCollection;

  static JSONObject viewList = new JSONObject();
  static CordovaInterface _cordova;
  static CordovaWebView _webView;


  public class RunnableUpdateViews implements Runnable{
    public JSONArray mProperty;
    public View mView;
    public ArrayList<RunnableUpdateViews> allStreamViews;


    public class CustomComparator implements Comparator<RunnableUpdateViews> {
      @Override
        public int compare(RunnableUpdateViews object1, RunnableUpdateViews object2) {
          return object2.getZIndex() - object1.getZIndex();
        }
    }

    public void updateZIndices(){
      allStreamViews =  new ArrayList<RunnableUpdateViews>();
      for (Map.Entry<String, RunnableSubscriber> entry : subscriberCollection.entrySet() ) { 
        allStreamViews.add( entry.getValue() ); 
      }
      if( myPublisher != null ){
        allStreamViews.add( myPublisher ); 
      }
      Collections.sort( allStreamViews, new CustomComparator() );

      for( RunnableUpdateViews viewContainer : allStreamViews ){
        ViewGroup parent = (ViewGroup) cordova.getActivity().findViewById(android.R.id.content);
        if (null != parent) {
          parent.removeView( viewContainer.mView );
          parent.addView(viewContainer.mView );
        }
      }
    }

    public int getZIndex(){
      try{
        return mProperty.getInt(5); 
      }catch( Exception e ) {
        return 0;
      }
    }

    @SuppressLint("NewApi")
    @Override
      public void run() {
        try{
          Log.i( TAG, "updating view in ui runnable" + mProperty.toString() );
          Log.i( TAG, "updating view in ui runnable " + mView.toString() );

          float widthRatio, heightRatio;

          // Ratios are index 6 & 7 on TB.updateViews, 8 & 9 on subscribe event, and 9 & 10 on TB.initPublisher
          int ratioIndex;
          if (mProperty.get(6) instanceof Number) {
              ratioIndex = 6;
          } else if (mProperty.get(8) instanceof Number) {
              ratioIndex = 8;
          } else {
              ratioIndex = 9;
          }

          widthRatio = (float) mProperty.getDouble(ratioIndex);
          heightRatio = (float) mProperty.getDouble(ratioIndex + 1);

          mView.setY( mProperty.getInt(1) * heightRatio );
          mView.setX( mProperty.getInt(2) * widthRatio );
          ViewGroup.LayoutParams params = mView.getLayoutParams();
          params.height = (int) (mProperty.getInt(4) * heightRatio);
          params.width = (int) (mProperty.getInt(3) * widthRatio);
          mView.setLayoutParams(params);
          updateZIndices();
        }catch( Exception e ){
          Log.i(TAG, "error when trying to retrieve properties while resizing properties");
        }
      }
  }

  public class RunnablePublisher extends RunnableUpdateViews implements 
    PublisherKit.PublisherListener, Publisher.CameraListener{
    //  property contains: [name, position.top, position.left, width, height, zIndex, publishAudio, publishVideo, cameraName] )
    public Publisher mPublisher;

    public RunnablePublisher( JSONArray args ){
      this.mProperty = args;

      // prevent dialog box from showing because it causes crash
      SharedPreferences prefs = cordova.getActivity().getApplicationContext().getSharedPreferences("permissions",
          Context.MODE_PRIVATE);
      Editor edit = prefs.edit();
      edit.clear();
      edit.putBoolean("opentok.publisher.accepted", true);
      edit.commit();
      cordova.getActivity().runOnUiThread( this );
    }

    public void setPropertyFromArray( JSONArray args ){
      this.mProperty = args;
    }

    public void startPublishing(){
      cordova.getActivity().runOnUiThread( this );
    }


    public void destroyPublisher(){
      ViewGroup parent = (ViewGroup) cordova.getActivity().findViewById(android.R.id.content);
        parent.removeView( this.mView );
        this.mPublisher.destroy();
        this.mPublisher = null;
    }
    
    public void run() {
      Log.i(TAG, "view running on UIVIEW!!!");
      if( mPublisher == null ){
        ViewGroup frame = (ViewGroup) cordova.getActivity().findViewById(android.R.id.content);
        String publisherName;
        try{
          publisherName = this.mProperty.getString(0);
        }catch(Exception e){
          publisherName = "Android-Publisher";
        }

        mPublisher = new Publisher(cordova.getActivity().getApplicationContext(), publisherName);
        mPublisher.setCameraListener(this);
        mPublisher.setPublisherListener(this);
        try{
          // Camera is swapped in streamCreated event
          if( compareStrings(this.mProperty.getString(7), "false") ){
            mPublisher.setPublishVideo(false); // default is true
          }
          if( compareStrings(this.mProperty.getString(6), "false") ){
            mPublisher.setPublishAudio(false); // default is true
          }
          Log.i(TAG, "all set up for publisher");
        }catch( Exception e ){
          Log.i(TAG, "error when trying to retrieve publish audio/video property");
        }
        this.mView = mPublisher.getView();
        frame.addView( this.mView );
      }
      if(sessionConnected && mPublisher != null){
        mSession.publish(mPublisher);
      }
      super.run();
    }
    
    // event listeners
    @Override
    public void onError(PublisherKit arg0, OpentokError arg1) {
      // TODO Auto-generated method stub
      
    }

    @Override
    public void onStreamCreated(PublisherKit arg0, Stream arg1) {
      Log.i(TAG, "publisher stream received");
      try{
        if( compareStrings(this.mProperty.getString(8), "back") ){
          Log.i(TAG, "swapping camera");
          mPublisher.swapCamera(); // default is front
        }
      }catch(Exception e){
        Log.i(TAG, "error when trying to retrieve cameraName property");
      }
      streamCollection.put(arg1.getStreamId(), arg1);
      triggerStreamCreated( arg1, "publisherEvents");
    }

    @Override
    public void onStreamDestroyed(PublisherKit arg0, Stream arg1) {
      streamCollection.remove( arg1.getStreamId() );<commit_msg>Fixes dropped calls and multiple streamCreated events<commit_after>package com.tokbox.cordova;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.opentok.android.Connection;
import com.opentok.android.OpentokError;
import com.opentok.android.Publisher;
import com.opentok.android.PublisherKit;
import com.opentok.android.Session;
import com.opentok.android.Stream;
import com.opentok.android.Subscriber;
import com.opentok.android.SubscriberKit;


public class OpenTokAndroidPlugin extends CordovaPlugin implements 
  Session.SessionListener, Session.ConnectionListener, Session.SignalListener, 
  Session.PublisherListener, Session.StreamPropertiesListener{
  
  private String sessionId;
  protected Session mSession;
  public static final String TAG = "OTPlugin";
  public boolean sessionConnected;
  public boolean publishCalled; // we need this because creating publisher before sessionConnected = crash
  public RunnablePublisher myPublisher;
  public HashMap<String, CallbackContext> myEventListeners;
  public HashMap<String, Connection> connectionCollection;
  public HashMap<String, Stream> streamCollection;
  public HashMap<String, RunnableSubscriber> subscriberCollection;

  static JSONObject viewList = new JSONObject();
  static CordovaInterface _cordova;
  static CordovaWebView _webView;


  public class RunnableUpdateViews implements Runnable{
    public JSONArray mProperty;
    public View mView;
    public ArrayList<RunnableUpdateViews> allStreamViews;


    public class CustomComparator implements Comparator<RunnableUpdateViews> {
      @Override
        public int compare(RunnableUpdateViews object1, RunnableUpdateViews object2) {
          return object2.getZIndex() - object1.getZIndex();
        }
    }

    public void updateZIndices(){
      allStreamViews =  new ArrayList<RunnableUpdateViews>();
      for (Map.Entry<String, RunnableSubscriber> entry : subscriberCollection.entrySet() ) { 
        allStreamViews.add( entry.getValue() ); 
      }
      if( myPublisher != null ){
        allStreamViews.add( myPublisher ); 
      }
      Collections.sort( allStreamViews, new CustomComparator() );

      for( RunnableUpdateViews viewContainer : allStreamViews ){
        ViewGroup parent = (ViewGroup) cordova.getActivity().findViewById(android.R.id.content);
        if (null != parent) {
          parent.removeView( viewContainer.mView );
          parent.addView(viewContainer.mView );
        }
      }
    }

    public int getZIndex(){
      try{
        return mProperty.getInt(5); 
      }catch( Exception e ) {
        return 0;
      }
    }

    @SuppressLint("NewApi")
    @Override
      public void run() {
        try{
          Log.i( TAG, "updating view in ui runnable" + mProperty.toString() );
          Log.i( TAG, "updating view in ui runnable " + mView.toString() );

          float widthRatio, heightRatio;

          // Ratios are index 6 & 7 on TB.updateViews, 8 & 9 on subscribe event, and 9 & 10 on TB.initPublisher
          int ratioIndex;
          if (mProperty.get(6) instanceof Number) {
              ratioIndex = 6;
          } else if (mProperty.get(8) instanceof Number) {
              ratioIndex = 8;
          } else {
              ratioIndex = 9;
          }

          widthRatio = (float) mProperty.getDouble(ratioIndex);
          heightRatio = (float) mProperty.getDouble(ratioIndex + 1);

          mView.setY( mProperty.getInt(1) * heightRatio );
          mView.setX( mProperty.getInt(2) * widthRatio );
          ViewGroup.LayoutParams params = mView.getLayoutParams();
          params.height = (int) (mProperty.getInt(4) * heightRatio);
          params.width = (int) (mProperty.getInt(3) * widthRatio);
          mView.setLayoutParams(params);
          updateZIndices();
        }catch( Exception e ){
          Log.i(TAG, "error when trying to retrieve properties while resizing properties");
        }
      }
  }

  public class RunnablePublisher extends RunnableUpdateViews implements 
    PublisherKit.PublisherListener, Publisher.CameraListener{
    //  property contains: [name, position.top, position.left, width, height, zIndex, publishAudio, publishVideo, cameraName] )
    public Publisher mPublisher;

    public RunnablePublisher( JSONArray args ){
      this.mProperty = args;

      // prevent dialog box from showing because it causes crash
      SharedPreferences prefs = cordova.getActivity().getApplicationContext().getSharedPreferences("permissions",
          Context.MODE_PRIVATE);
      Editor edit = prefs.edit();
      edit.clear();
      edit.putBoolean("opentok.publisher.accepted", true);
      edit.commit();
    }

    public void setPropertyFromArray( JSONArray args ){
      this.mProperty = args;
    }

    public void startPublishing(){
      cordova.getActivity().runOnUiThread( this );
    }


    public void destroyPublisher(){
      ViewGroup parent = (ViewGroup) cordova.getActivity().findViewById(android.R.id.content);
        parent.removeView( this.mView );
        this.mPublisher.destroy();
        this.mPublisher = null;
    }
    
    public void run() {
      Log.i(TAG, "view running on UIVIEW!!!");
      if( mPublisher == null ){
        ViewGroup frame = (ViewGroup) cordova.getActivity().findViewById(android.R.id.content);
        String publisherName;
        try{
          publisherName = this.mProperty.getString(0);
        }catch(Exception e){
          publisherName = "Android-Publisher";
        }

        mPublisher = new Publisher(cordova.getActivity().getApplicationContext(), publisherName);
        mPublisher.setCameraListener(this);
        mPublisher.setPublisherListener(this);
        try{
          // Camera is swapped in streamCreated event
          if( compareStrings(this.mProperty.getString(7), "false") ){
            mPublisher.setPublishVideo(false); // default is true
          }
          if( compareStrings(this.mProperty.getString(6), "false") ){
            mPublisher.setPublishAudio(false); // default is true
          }
          Log.i(TAG, "all set up for publisher");
        }catch( Exception e ){
          Log.i(TAG, "error when trying to retrieve publish audio/video property");
        }
        this.mView = mPublisher.getView();
        frame.addView( this.mView );
        mSession.publish(mPublisher);
      }
      super.run();
    }
    
    // event listeners
    @Override
    public void onError(PublisherKit arg0, OpentokError arg1) {
      // TODO Auto-generated method stub
      
    }

    @Override
    public void onStreamCreated(PublisherKit arg0, Stream arg1) {
      Log.i(TAG, "publisher stream received");
      try{
        if( compareStrings(this.mProperty.getString(8), "back") ){
          Log.i(TAG, "swapping camera");
          mPublisher.swapCamera(); // default is front
        }
      }catch(Exception e){
        Log.i(TAG, "error when trying to retrieve cameraName property");
      }
      streamCollection.put(arg1.getStreamId(), arg1);
      triggerStreamCreated( arg1, "publisherEvents");
    }

    @Override
    public void onStreamDestroyed(PublisherKit arg0, Stream arg1) {
      streamCollection.remove( arg1.getStreamId() );
{'fraction_non_alphanumeric': 0.09876151159098126, 'fraction_numerical': 0.004699904731660844, 'mean_word_length': 3.0271099744245524, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6342645', 'n_tokens_mistral': 4488, 'n_tokens_neox': 4261, 'n_words': 1029}