gt:         super.onLayout(changed, left, top, right, bottom);
context: /**
   * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
   * This file is part of CSipSimple.
   *
   *  CSipSimple is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *  If you own a pjsip commercial license you can also redistribute it
   *  and/or modify it under the terms of the GNU Lesser General Public License
   *  as an android library.
   *
   *  CSipSimple is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with CSipSimple.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  package com.csipsimple.ui.incall;
  
  import android.content.Context;
  import android.content.Intent;
  import android.os.Handler;
  import android.os.Message;
  import android.text.TextUtils;
  import android.util.AttributeSet;
  import android.util.FloatMath;
  import android.view.LayoutInflater;
  import android.view.SurfaceView;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.view.ViewGroup;
  import android.view.animation.Animation;
  import android.view.animation.AnimationUtils;
  import android.widget.Chronometer;
  import android.widget.FrameLayout;
  import android.widget.ImageView;
  import android.widget.RelativeLayout;
  import android.widget.TextView;
  
  import com.actionbarsherlock.internal.utils.UtilityWrapper;
  import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
  import com.actionbarsherlock.internal.view.menu.ActionMenuView;
  import com.actionbarsherlock.internal.view.menu.MenuBuilder;
  import com.actionbarsherlock.internal.view.menu.MenuBuilder.Callback;
  import com.actionbarsherlock.view.MenuInflater;
  import com.actionbarsherlock.view.MenuItem;
  import tw.net.ezcall.R;
  import com.csipsimple.api.SipCallSession;
  import com.csipsimple.api.SipCallSession.MediaState;
  import com.csipsimple.api.SipConfigManager;
  import com.csipsimple.api.SipManager;
  import com.csipsimple.api.SipProfile;
  import com.csipsimple.api.SipUri;
  import com.csipsimple.api.SipUri.ParsedSipContactInfos;
  import com.csipsimple.models.CallerInfo;
  import com.csipsimple.service.SipService;
  import com.csipsimple.utils.ContactsAsyncHelper;
  import com.csipsimple.utils.CustomDistribution;
  import com.csipsimple.utils.ExtraPlugins;
  import com.csipsimple.utils.ExtraPlugins.DynActivityPlugin;
  import com.csipsimple.utils.Log;
  import com.csipsimple.utils.PreferencesProviderWrapper;
  
  import org.webrtc.videoengine.ViERenderer;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  public class InCallCard extends FrameLayout implements OnClickListener, Callback {
  
      private static final String THIS_FILE = "InCallCard";
      
      private SipCallSession callInfo;
      private String cachedRemoteUri = "";
      private int cachedInvState = SipCallSession.InvState.INVALID;
      private int cachedMediaState = SipCallSession.MediaState.ERROR;
      private boolean cachedCanRecord = false;
      private boolean cachedIsRecording = false;
      private boolean cachedIsHold = false;
      private boolean cachedVideo = false;
      private ImageView photo;
      private TextView remoteName, remoteSipAddress, callStatusText, callSecureText;
      private ViewGroup callSecureBar;
      private Chronometer elapsedTime;
      private SurfaceView renderView;
      private PreferencesProviderWrapper prefs;
      private ViewGroup endCallBar;
      private MenuBuilder btnMenuBuilder;
      private boolean hasVideo = false;
      private boolean canVideo = false;
      private boolean cachedZrtpVerified;
      private boolean cachedZrtpActive;
  
      private ActionMenuPresenter mActionMenuPresenter;
  
      private Map<String, DynActivityPlugin> incallPlugins;
  
  
      public InCallCard(Context context, AttributeSet attrs) {
          super(context, attrs);
          LayoutInflater inflater = LayoutInflater.from(context);
          inflater.inflate(R.layout.in_call_card, this, true);
  
          prefs = new PreferencesProviderWrapper(context);
          canVideo = prefs.getPreferenceBooleanValue(SipConfigManager.USE_VIDEO);
          initControllerView();
          
          incallPlugins = ExtraPlugins.getDynActivityPlugins(context, SipManager.ACTION_INCALL_PLUGIN);
      }
  
      private void initControllerView() {
          photo = (ImageView) findViewById(R.id.contact_photo);
          remoteName = (TextView) findViewById(R.id.contact_name_display_name);
          remoteSipAddress = (TextView) findViewById(R.id.contact_name_sip_address);
          elapsedTime = (Chronometer) findViewById(R.id.elapsedTime);
          callStatusText = (TextView) findViewById(R.id.call_status_text);
          callSecureBar = (ViewGroup) findViewById(R.id.call_secure_bar);
          callSecureText = (TextView) findViewById(R.id.call_secure_text);
          endCallBar = (ViewGroup) findViewById(R.id.end_call_bar);
  
  
          View btn;
          btn = findViewById(R.id.endButton);
          btn.setOnClickListener(this);
  
          btnMenuBuilder = new MenuBuilder(getContext());
          btnMenuBuilder.setCallback(this);
          MenuInflater inflater = new MenuInflater(getContext());
          inflater.inflate(R.menu.in_call_card_menu, btnMenuBuilder);
          
          mActionMenuPresenter = new ActionMenuPresenter(getContext());
          mActionMenuPresenter.setReserveOverflow(true);
          
          btnMenuBuilder.addMenuPresenter(mActionMenuPresenter);
          
          updateMenuView();
      }
      
      private boolean added = false;
      private void updateMenuView() {
          int w = getWidth();
          if(w <= 0) {
              w = getResources().getDisplayMetrics().widthPixels;
          }
          w -= 100;
          if(!added) {
              final FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                      FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
              ViewGroup menuViewWrapper = (ViewGroup) findViewById(R.id.call_action_bar);
              mActionMenuPresenter.setReserveOverflow(true);
              mActionMenuPresenter.setWidthLimit(w, true);
              // Use width limit (this means we don't care item limits 
              mActionMenuPresenter.setItemLimit(20);
              ActionMenuView menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(menuViewWrapper);
              UtilityWrapper.getInstance().setBackgroundDrawable(menuView, null);
              menuViewWrapper.addView(menuView, layoutParams);
              added = true;
          }else {
              mActionMenuPresenter.setWidthLimit(w, true);
              mActionMenuPresenter.updateMenuView(true);
          }
      }
  
      public synchronized void setCallState(SipCallSession aCallInfo) {
          callInfo = aCallInfo;
          if (callInfo == null) {
              updateElapsedTimer();
              cachedInvState = SipCallSession.InvState.INVALID;
              cachedMediaState = SipCallSession.MediaState.ERROR;
              cachedCanRecord = false;
              cachedIsRecording = false;
              cachedIsHold = false;
              cachedVideo = false;
              cachedZrtpActive = false;
              cachedZrtpVerified = false;
              return;
          }
  
          Log.d(THIS_FILE, "Set call state : " + callInfo.getCallState());
          
          updateRemoteName();
          updateCallStateBar();
          updateQuickActions();
          updateElapsedTimer();
  
          cachedInvState = callInfo.getCallState();
          cachedMediaState = callInfo.getMediaStatus();
          cachedCanRecord = callInfo.canRecord();
          cachedIsRecording = callInfo.isRecording();
          cachedIsHold = callInfo.isLocalHeld();
          cachedVideo = callInfo.mediaHasVideo();
          cachedZrtpActive = callInfo.getHasZrtp();
          cachedZrtpVerified = callInfo.isZrtpSASVerified();
          
          // VIDEO STUFF -- EXPERIMENTAL
          if(canVideo) {
              if (callInfo.getCallId() >= 0 && cachedVideo) {
                  if (renderView == null) {
                      renderView = ViERenderer.CreateRenderer(getContext(), true);
                      photo.setVisibility(View.GONE);
                      RelativeLayout container = (RelativeLayout) findViewById(R.id.call_card_container);
                      RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                              RelativeLayout.LayoutParams.MATCH_PARENT,
                              RelativeLayout.LayoutParams.MATCH_PARENT);
                      lp.addRule(RelativeLayout.ALIGN_LEFT, RelativeLayout.TRUE);
                      lp.addRule(RelativeLayout.ALIGN_RIGHT, RelativeLayout.TRUE);
                      lp.addRule(RelativeLayout.ALIGN_TOP, RelativeLayout.TRUE);
                      lp.addRule(RelativeLayout.ABOVE, R.id.call_action_bar);
                      renderView.setLayoutParams(lp);
                      container.addView(renderView, 0);
  
                      Log.d(THIS_FILE, "Render window added");
                      SipService.setVideoWindow(callInfo.getCallId(), renderView, false);
                      
                      View v = findViewById(R.id.end_call_bar);
                      ViewGroup.LayoutParams lp2 = v.getLayoutParams();
                      lp2.height = ViewGroup.LayoutParams.WRAP_CONTENT; 
                      v.setLayoutParams(lp2);
                  }
                  hasVideo = true;
              }else {
                  if(renderView != null) {
                      renderView.setVisibility(View.GONE);
                      photo.setVisibility(View.VISIBLE);
                  }
                  hasVideo = false;
              }
          }
          if (onTriggerListener != null) {
              onTriggerListener.onDisplayVideo(hasVideo && canVideo);
          }
          // End of video stuff
          
          //requestLayout();
          /*
          if(dragListener != null) {
              dragListener.setCallState(callInfo);
          }
          */
      }
      
      /* We accept height twice than width */
      private static float minRatio = 0.5f;
      /* We accept width 1/4 bigger than height */ 
      private static float maxRatio = 1.25f;
      
      private static float minButtonRation = 0.75f;
      
  
      private final Handler handler = new Handler();
      private final Runnable postLayout = new Runnable() {
          @Override
          public void run() {
              float w = getWidth();
              float h = getHeight();
              if(w > 0 && h > 0) {
                  float currentRatio = w/h;
                  float newWidth = w;
                  float newHeight = h;
                  Log.d(THIS_FILE, "Current ratio is " + currentRatio);
                  if(currentRatio < minRatio) {
                      newHeight = w / minRatio;
                      int padding = (int) FloatMath.floor((h - newHeight) /2);
                      setPadding(0, padding, 0, padding);
                  }else if(currentRatio > maxRatio) {
                      newWidth = h * maxRatio;
                      int padding = (int) FloatMath.floor((w - newWidth) /2);
                      setPadding(padding, 0, padding, 0);
                  }else {
                      setPadding(0, 0, 0, 0);
                  }
                  View v = findViewById(R.id.end_call_bar);
                  ViewGroup.LayoutParams lp = v.getLayoutParams();
                  if(currentRatio < minButtonRation && !hasVideo) {
                      lp.height = (int) ((1.0f - minButtonRation) * newHeight); 
                  }else {
                      lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; 
                  }
                  v.setLayoutParams(lp);
                  updateMenuView();
              }
          }
      };
  
      
      @Override
      protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
          if(changed) {
              handler.postDelayed(postLayout, 100);
          }
          
  