diff --git a/AndroidManifest.xml b/AndroidManifest.xml index de8bfba99..5d113f2d6 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -73,7 +73,7 @@ + android:launchMode="singleInstance"> diff --git a/res/layout-land/incall.xml b/res/layout-land/incall.xml index d33e494aa..5711885af 100644 --- a/res/layout-land/incall.xml +++ b/res/layout-land/incall.xml @@ -34,7 +34,9 @@ android:paddingTop="20dp" android:src="@drawable/switch_camera" android:visibility="gone" /> - + + + - \ No newline at end of file + diff --git a/res/layout/incall.xml b/res/layout/incall.xml index b01398f27..6fbc82d0f 100644 --- a/res/layout/incall.xml +++ b/res/layout/incall.xml @@ -7,7 +7,7 @@ + android:layout_height="match_parent" > - \ No newline at end of file + diff --git a/res/layout/main.xml b/res/layout/main.xml index 0e97f0c85..8e6709647 100644 --- a/res/layout/main.xml +++ b/res/layout/main.xml @@ -1,12 +1,13 @@ - \ No newline at end of file + diff --git a/res/values/strings.xml b/res/values/strings.xml index 5a8a8bcde..76a823161 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -263,7 +263,7 @@ CONNECTING ERROR - Number or adress + Number or address Add to contacts button diff --git a/src/org/linphone/AudioCallFragment.java b/src/org/linphone/AudioCallFragment.java index d952f9d77..614b66690 100644 --- a/src/org/linphone/AudioCallFragment.java +++ b/src/org/linphone/AudioCallFragment.java @@ -51,7 +51,6 @@ public class AudioCallFragment extends Fragment { private RelativeLayout callsList; private LayoutInflater inflater; private ViewGroup container; - private InCallActivity inCallActivity; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -144,20 +143,20 @@ public class AudioCallFragment extends Fragment { @Override public void onAttach(Activity activity) { super.onAttach(activity); - inCallActivity = (InCallActivity) activity; - inCallActivity.bindAudioFragment(this); + if (InCallActivity.isInstanciated()) { + InCallActivity.instance().bindAudioFragment(this); + } } @Override public void onStart() { super.onStart(); - if (inCallActivity == null) { - return; - } - + // Just to be sure we have incall controls - inCallActivity.setCallControlsVisibleAndRemoveCallbacks(); + if (InCallActivity.isInstanciated()) { + InCallActivity.instance().setCallControlsVisibleAndRemoveCallbacks(); + } } @Override @@ -177,7 +176,7 @@ public class AudioCallFragment extends Fragment { int index = 0; if (LinphoneManager.getLc().getCallsNb() == 0) { - inCallActivity.goBackToDialer(); + InCallActivity.instance().goBackToDialer(); return; } diff --git a/src/org/linphone/InCallActivity.java b/src/org/linphone/InCallActivity.java index 5bbb7a512..02d599170 100644 --- a/src/org/linphone/InCallActivity.java +++ b/src/org/linphone/InCallActivity.java @@ -41,9 +41,11 @@ import android.support.v4.app.FragmentTransaction; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; +import android.widget.AdapterView; import android.widget.ImageView; import android.widget.LinearLayout; @@ -367,16 +369,20 @@ public class InCallActivity extends FragmentActivity implements public void displayVideoCallControlsIfHidden() { if (mControlsLayout != null) { if (mControlsLayout.getVisibility() == View.GONE) { - if (InCallActivity.this.getResources().getBoolean(R.bool.disable_animations)) { + if (getResources().getBoolean(R.bool.disable_animations)) { mControlsLayout.setVisibility(View.VISIBLE); - switchCamera.setVisibility(View.VISIBLE); + if (AndroidCameraConfiguration.retrieveCameras().length > 1) { + switchCamera.setVisibility(View.VISIBLE); + } } else { Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_in_bottom_to_top); animation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { mControlsLayout.setVisibility(View.VISIBLE); - switchCamera.setVisibility(View.VISIBLE); + if (AndroidCameraConfiguration.retrieveCameras().length > 1) { + switchCamera.setVisibility(View.VISIBLE); + } } @Override @@ -390,9 +396,9 @@ public class InCallActivity extends FragmentActivity implements mControlsLayout.startAnimation(animation); switchCamera.startAnimation(AnimationUtils.loadAnimation(this, R.anim.slide_in_top_to_bottom)); } + + resetControlsHidingCallBack(); } - - resetControlsHidingCallBack(); } } @@ -400,20 +406,21 @@ public class InCallActivity extends FragmentActivity implements if (controlsHandler != null && mControls != null) { controlsHandler.removeCallbacks(mControls); } + mControls = null; if (isVideoEnabled) { controlsHandler.postDelayed(mControls = new Runnable() { public void run() { hideNumpad(); - if (InCallActivity.this.getResources().getBoolean(R.bool.disable_animations)) { + if (getResources().getBoolean(R.bool.disable_animations)) { transfer.setVisibility(View.INVISIBLE); addCall.setVisibility(View.INVISIBLE); mControlsLayout.setVisibility(View.GONE); switchCamera.setVisibility(View.INVISIBLE); options.setImageResource(R.drawable.options); } else { - Animation animation = AnimationUtils.loadAnimation(InCallActivity.this, R.anim.slide_out_top_to_bottom); + Animation animation = AnimationUtils.loadAnimation(instance, R.anim.slide_out_top_to_bottom); animation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { @@ -435,7 +442,7 @@ public class InCallActivity extends FragmentActivity implements } }); mControlsLayout.startAnimation(animation); - switchCamera.startAnimation(AnimationUtils.loadAnimation(InCallActivity.this, R.anim.slide_out_bottom_to_top)); + switchCamera.startAnimation(AnimationUtils.loadAnimation(instance, R.anim.slide_out_bottom_to_top)); } } }, SECONDS_BEFORE_HIDING_CONTROLS); @@ -445,8 +452,8 @@ public class InCallActivity extends FragmentActivity implements public void setCallControlsVisibleAndRemoveCallbacks() { if (controlsHandler != null && mControls != null) { controlsHandler.removeCallbacks(mControls); - mControls = null; } + mControls = null; mControlsLayout.setVisibility(View.VISIBLE); switchCamera.setVisibility(View.INVISIBLE); @@ -483,6 +490,10 @@ public class InCallActivity extends FragmentActivity implements } private void hideOrDisplayNumpad() { + if (numpad == null) { + return; + } + if (numpad.getVisibility() == View.VISIBLE) { hideNumpad(); } else { @@ -599,8 +610,7 @@ public class InCallActivity extends FragmentActivity implements } @Override - public void onCallStateChanged(LinphoneCall call, State state, - String message) { + public void onCallStateChanged(LinphoneCall call, State state, String message) { if (LinphoneManager.getLc().getCallsNb() == 0) { finish(); return; @@ -630,8 +640,7 @@ public class InCallActivity extends FragmentActivity implements } @Override - public void onCallEncryptionChanged(LinphoneCall call, boolean encrypted, - String authenticationToken) { + public void onCallEncryptionChanged(LinphoneCall call, boolean encrypted, String authenticationToken) { if (status != null) { status.refreshStatusItems(); } @@ -653,16 +662,36 @@ public class InCallActivity extends FragmentActivity implements @Override protected void onPause() { - LinphoneManager.removeListener(this); - LinphoneManager.stopProximitySensorForActivity(this); - super.onPause(); + + if (controlsHandler != null && mControls != null) { + controlsHandler.removeCallbacks(mControls); + } + mControls = null; + + LinphoneManager.stopProximitySensorForActivity(this); + LinphoneManager.removeListener(this); } @Override protected void onDestroy() { - instance = null; super.onDestroy(); + + unbindDrawables(findViewById(R.id.topLayout)); + instance = null; + System.gc(); + } + + private void unbindDrawables(View view) { + if (view.getBackground() != null) { + view.getBackground().setCallback(null); + } + if (view instanceof ViewGroup && !(view instanceof AdapterView)) { + for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { + unbindDrawables(((ViewGroup) view).getChildAt(i)); + } + ((ViewGroup) view).removeAllViews(); + } } @Override diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index ce4f6f37b..5423534ac 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -60,9 +60,11 @@ import android.support.v4.app.FragmentTransaction; import android.view.KeyEvent; import android.view.OrientationEventListener; import android.view.View; +import android.view.ViewGroup; import android.view.View.OnClickListener; import android.view.WindowManager; import android.view.animation.AnimationUtils; +import android.widget.AdapterView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -647,20 +649,24 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene } @Override public void onOrientationChanged(final int o) { - if (o == OrientationEventListener.ORIENTATION_UNKNOWN) return; + if (o == OrientationEventListener.ORIENTATION_UNKNOWN) { + return; + } - int degrees=270; - if (o < 45 || o >315) degrees=0; - else if (o<135) degrees=90; - else if (o<225) degrees=180; + int degrees = 270; + if (o < 45 || o >315) degrees = 0; + else if (o < 135) degrees = 90; + else if (o < 225) degrees = 180; - if (mAlwaysChangingPhoneAngle == degrees) return; + if (mAlwaysChangingPhoneAngle == degrees) { + return; + } mAlwaysChangingPhoneAngle = degrees; Log.d("Phone orientation changed to ", degrees); int rotation = (360 - degrees) % 360; - LinphoneCore lc=LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc!=null){ + LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + if (lc != null){ lc.setDeviceRotation(rotation); LinphoneCall currentCall = lc.getCurrentCall(); if (currentCall != null && currentCall.cameraEnabled() && currentCall.getCurrentParamsCopy().getVideoEnabled()) { @@ -822,7 +828,29 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene chatStorage.close(); chatStorage = null; } + + if (mOrientationHelper != null) { + mOrientationHelper.disable(); + mOrientationHelper = null; + } + + instance = null; super.onDestroy(); + + unbindDrawables(findViewById(R.id.topLayout)); + System.gc(); + } + + private void unbindDrawables(View view) { + if (view != null && view.getBackground() != null) { + view.getBackground().setCallback(null); + } + if (view instanceof ViewGroup && !(view instanceof AdapterView)) { + for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { + unbindDrawables(((ViewGroup) view).getChildAt(i)); + } + ((ViewGroup) view).removeAllViews(); + } } @Override diff --git a/src/org/linphone/VideoCallFragment.java b/src/org/linphone/VideoCallFragment.java index 79d6beab2..ecf0d169c 100644 --- a/src/org/linphone/VideoCallFragment.java +++ b/src/org/linphone/VideoCallFragment.java @@ -25,7 +25,6 @@ import org.linphone.core.Log; import org.linphone.mediastream.video.AndroidVideoWindowImpl; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; -import android.app.Activity; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -34,7 +33,6 @@ import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.ScaleGestureDetector; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; @@ -49,7 +47,6 @@ public class VideoCallFragment extends Fragment implements OnGestureListener, On private SurfaceView mVideoView; private SurfaceView mCaptureView; private AndroidVideoWindowImpl androidVideoWindowImpl; - private InCallActivity inCallActivity; private GestureDetector mGestureDetector; private float mZoomFactor = 1.f; private float mZoomCenterX, mZoomCenterY; @@ -70,7 +67,6 @@ public class VideoCallFragment extends Fragment implements OnGestureListener, On mCaptureView = (SurfaceView) view.findViewById(R.id.videoCaptureSurface); mCaptureView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // Warning useless because value is ignored and automatically set by new APIs. - /* force surfaces Z ordering */ fixZOrder(mVideoView, mCaptureView); androidVideoWindowImpl = new AndroidVideoWindowImpl(mVideoView, mCaptureView); @@ -107,7 +103,7 @@ public class VideoCallFragment extends Fragment implements OnGestureListener, On } mGestureDetector.onTouchEvent(event); - inCallActivity.displayVideoCallControlsIfHidden(); + InCallActivity.instance().displayVideoCallControlsIfHidden(); return true; } }); @@ -115,12 +111,6 @@ public class VideoCallFragment extends Fragment implements OnGestureListener, On return view; } - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - inCallActivity = (InCallActivity) activity; - } - private void fixZOrder(SurfaceView video, SurfaceView preview) { video.setZOrderOnTop(false); preview.setZOrderOnTop(true); @@ -168,13 +158,13 @@ public class VideoCallFragment extends Fragment implements OnGestureListener, On LinphoneManager.getLc().setVideoWindow(null); } - super.onPause(); - if (mVideoView != null) ((GLSurfaceView) mVideoView).onPause(); + + super.onPause(); } - public boolean onScale(ScaleGestureDetector detector) { + public boolean onScale(CompatibilityScaleGestureDetector detector) { mZoomFactor *= detector.getScaleFactor(); // Don't let the object get too small or too large. mZoomFactor = Math.max(0.1f, Math.min(mZoomFactor, mVideoView.getHeight() / LinphoneManager.getLc().getPreferredVideoSize().height)); @@ -232,10 +222,24 @@ public class VideoCallFragment extends Fragment implements OnGestureListener, On @Override public void onDestroy() { + getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + if (androidVideoWindowImpl != null) { // Prevent linphone from crashing if correspondent hang up while you are rotating androidVideoWindowImpl.release(); + androidVideoWindowImpl = null; + mCaptureView = null; + mVideoView = null; } + if (mGestureDetector != null) { + mGestureDetector.setOnDoubleTapListener(null); + mGestureDetector = null; + } + if (mScaleDetector != null) { + mScaleDetector.destroy(); + mScaleDetector = null; + } + super.onDestroy(); } diff --git a/src/org/linphone/compatibility/Compatibility.java b/src/org/linphone/compatibility/Compatibility.java index 4fb383039..275664d56 100644 --- a/src/org/linphone/compatibility/Compatibility.java +++ b/src/org/linphone/compatibility/Compatibility.java @@ -165,7 +165,7 @@ public class Compatibility { public static CompatibilityScaleGestureDetector getScaleGestureDetector(Context context, CompatibilityScaleGestureListener listener) { if (Version.sdkAboveOrEqual(8)) { CompatibilityScaleGestureDetector csgd = new CompatibilityScaleGestureDetector(context); - csgd.addListener(listener); + csgd.setOnScaleListener(listener); return csgd; } return null; diff --git a/src/org/linphone/compatibility/CompatibilityScaleGestureDetector.java b/src/org/linphone/compatibility/CompatibilityScaleGestureDetector.java index bbdc50d4e..68dc99b79 100644 --- a/src/org/linphone/compatibility/CompatibilityScaleGestureDetector.java +++ b/src/org/linphone/compatibility/CompatibilityScaleGestureDetector.java @@ -14,7 +14,7 @@ public class CompatibilityScaleGestureDetector extends ScaleGestureDetector.Simp detector = new ScaleGestureDetector(context, this); } - public void addListener(CompatibilityScaleGestureListener newListener) { + public void setOnScaleListener(CompatibilityScaleGestureListener newListener) { listener = newListener; } @@ -28,6 +28,15 @@ public class CompatibilityScaleGestureDetector extends ScaleGestureDetector.Simp return false; } - return listener.onScale(detector); + return listener.onScale(this); } + + public float getScaleFactor() { + return detector.getScaleFactor(); + } + + public void destroy() { + listener = null; + detector = null; + } } \ No newline at end of file diff --git a/src/org/linphone/compatibility/CompatibilityScaleGestureListener.java b/src/org/linphone/compatibility/CompatibilityScaleGestureListener.java index 517f6605b..67ffcfc57 100644 --- a/src/org/linphone/compatibility/CompatibilityScaleGestureListener.java +++ b/src/org/linphone/compatibility/CompatibilityScaleGestureListener.java @@ -1,7 +1,6 @@ package org.linphone.compatibility; -import android.view.ScaleGestureDetector; public interface CompatibilityScaleGestureListener { - public boolean onScale(ScaleGestureDetector detector); + public boolean onScale(CompatibilityScaleGestureDetector detector); } \ No newline at end of file diff --git a/src/org/linphone/ui/CallButton.java b/src/org/linphone/ui/CallButton.java index 7942b7b8d..4f64e8527 100644 --- a/src/org/linphone/ui/CallButton.java +++ b/src/org/linphone/ui/CallButton.java @@ -56,9 +56,9 @@ public class CallButton extends ImageView implements OnClickListener, AddressAwa if (getContext().getResources().getBoolean(R.bool.call_last_log_if_adress_is_empty)) { LinphoneCallLog[] logs = LinphoneManager.getLc().getCallLogs(); LinphoneCallLog log = null; - for (int i = logs.length - 1; i >= 0; i--) { - if (logs[i].getDirection() == CallDirection.Outgoing) { - log = logs[i]; + for (LinphoneCallLog l : logs) { + if (l.getDirection() == CallDirection.Outgoing) { + log = l; break; } } diff --git a/src/org/linphone/ui/Digit.java b/src/org/linphone/ui/Digit.java index b2846470a..c086c7098 100644 --- a/src/org/linphone/ui/Digit.java +++ b/src/org/linphone/ui/Digit.java @@ -110,7 +110,7 @@ public class Digit extends Button implements AddressAware { if (lBegin == -1) { lBegin = mAddress.length(); } - if (lBegin >=0) { + if (lBegin >= 0) { mAddress.getEditableText().insert(lBegin,String.valueOf(mKeyCode)); } } @@ -127,11 +127,11 @@ public class Digit extends Button implements AddressAware { LinphoneCore lc = LinphoneManager.getLc(); if (event.getAction() == MotionEvent.ACTION_DOWN && !mIsDtmfStarted) { LinphoneManager.getInstance().playDtmf(getContext().getContentResolver(), mKeyCode); - mIsDtmfStarted=true; + mIsDtmfStarted = true; } else { if (event.getAction() == MotionEvent.ACTION_UP) { lc.stopDtmf(); - mIsDtmfStarted=false; + mIsDtmfStarted = false; } } return false; @@ -151,7 +151,7 @@ public class Digit extends Button implements AddressAware { if (lBegin == -1) { lBegin = mAddress.getEditableText().length(); } - if (lBegin >=0) { + if (lBegin >= 0) { mAddress.getEditableText().insert(lBegin,"+"); } return true;