From b70d5b0e96f22e2235de1b967774ec1c1808a951 Mon Sep 17 00:00:00 2001 From: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com> Date: Fri, 8 Jul 2016 16:50:14 -0400 Subject: [PATCH] call: add connecting animation Brings a pulse animation on contact avatar while calling Clears wrong layout instructions and use ButterKnife for views injections. We use a different layout file in landscape to better use the available screen estate. Change-Id: Ie40f64bc8951b29cfc2c6b1c7640e05de149ccf9 Tuleap: #834 --- ring-android/app/build.gradle | 1 + .../java/cx/ring/client/CallActivity.java | 12 +- .../java/cx/ring/fragments/CallFragment.java | 332 +++++++++--------- .../src/main/res/layout-land/frag_call.xml | 218 ++++++++++++ .../main/res/layout/activity_call_layout.xml | 2 +- .../app/src/main/res/layout/frag_call.xml | 109 +++--- 6 files changed, 461 insertions(+), 213 deletions(-) create mode 100644 ring-android/app/src/main/res/layout-land/frag_call.xml diff --git a/ring-android/app/build.gradle b/ring-android/app/build.gradle index 2b94327a1..9408560f5 100644 --- a/ring-android/app/build.gradle +++ b/ring-android/app/build.gradle @@ -21,6 +21,7 @@ dependencies { compile 'com.google.zxing:core:3.2.1' compile 'com.journeyapps:zxing-android-embedded:3.2.0@aar' compile 'com.jakewharton:butterknife:8.1.0' + compile 'com.skyfishjy.ripplebackground:library:1.0.1' apt 'com.jakewharton:butterknife-compiler:8.1.0' } diff --git a/ring-android/app/src/main/java/cx/ring/client/CallActivity.java b/ring-android/app/src/main/java/cx/ring/client/CallActivity.java index 71b1518e3..e3765fcd7 100644 --- a/ring-android/app/src/main/java/cx/ring/client/CallActivity.java +++ b/ring-android/app/src/main/java/cx/ring/client/CallActivity.java @@ -58,7 +58,7 @@ import cx.ring.utils.CallProximityManager; import static cx.ring.service.LocalService.Callbacks; -public class CallActivity extends AppCompatActivity implements Callbacks, CallFragment.Callbacks, CallProximityManager.ProximityDirector { +public class CallActivity extends AppCompatActivity implements Callbacks, CallFragment.ConversationCallbacks, CallProximityManager.ProximityDirector { static final String TAG = CallActivity.class.getSimpleName(); public static final String ACTION_CALL = BuildConfig.APPLICATION_ID + ".action.call"; @@ -96,7 +96,7 @@ public class CallActivity extends AppCompatActivity implements Callbacks, CallFr setContentView(R.layout.activity_call_layout); - mMainView = findViewById(R.id.maincalllayout); + mMainView = findViewById(R.id.main_call_layout); mMainView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -135,6 +135,12 @@ public class CallActivity extends AppCompatActivity implements Callbacks, CallFr showSystemUI(); } + // Reload a new view + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + mCurrentCallFragment = new CallFragment(); + fragmentTransaction.replace(R.id.main_call_layout, mCurrentCallFragment).commit(); + super.onConfigurationChanged(newConfig); } @@ -249,7 +255,7 @@ public class CallActivity extends AppCompatActivity implements Callbacks, CallFr FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); mCurrentCallFragment = new CallFragment(); - fragmentTransaction.add(R.id.maincalllayout, mCurrentCallFragment).commit(); + fragmentTransaction.add(R.id.main_call_layout, mCurrentCallFragment).commit(); hideSystemUI(); } diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java index b6a0a7809..8f31c979a 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java +++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java @@ -37,6 +37,7 @@ import android.os.Bundle; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.RemoteException; +import android.support.annotation.Nullable; import android.support.v4.app.NotificationManagerCompat; import android.support.v7.app.ActionBar; import android.text.Editable; @@ -50,7 +51,6 @@ import android.view.MenuItem; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.Button; @@ -61,9 +61,14 @@ import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.ViewSwitcher; +import com.skyfishjy.library.RippleBackground; + import java.lang.ref.WeakReference; import java.util.HashMap; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import cx.ring.R; import cx.ring.adapters.ContactPictureTask; import cx.ring.client.ConversationActivity; @@ -81,7 +86,7 @@ import cx.ring.utils.KeyboardVisibilityManager; public class CallFragment extends Fragment implements CallInterface { - static private final String TAG = CallFragment.class.getSimpleName(); + static final private String TAG = CallFragment.class.getSimpleName(); public static final int REQUEST_TRANSFER = 10; @@ -90,38 +95,65 @@ public class CallFragment extends Fragment implements CallInterface { // Screen wake lock for incoming call private WakeLock mScreenWakeLock; - private View contactBubbleLayout; - private ImageView contactBubbleView; - private TextView contactBubbleTxt; - private TextView contactBubbleNumTxt; - private View acceptButton; - private View refuseButton; - private View hangupButton; - private View securityIndicator; + + @BindView(R.id.contact_bubble_layout) + View contactBubbleLayout; + + @BindView(R.id.contact_bubble) + ImageView contactBubbleView; + + @BindView(R.id.contact_bubble_txt) + TextView contactBubbleTxt; + + @BindView(R.id.contact_bubble_num_txt) + TextView contactBubbleNumTxt; + + @BindView(R.id.call_accept_btn) + View acceptButton; + + @BindView(R.id.call_refuse_btn) + View refuseButton; + + @BindView(R.id.call_hangup_btn) + View hangupButton; + + @BindView(R.id.call_status_txt) + TextView mCallStatusTxt; + + @BindView(R.id.security_indicator) + View securityIndicator; + + @BindView(R.id.security_switcher) + ViewSwitcher mSecuritySwitch; + + @BindView(R.id.dialpad_edit_text) + EditText mNumeralDialEditText; + + @BindView(R.id.ripple_animation) + RippleBackground mPulseAnimation; + + @BindView(R.id.video_preview_surface) + SurfaceView mVideoSurface = null; + private MenuItem speakerPhoneBtn = null; private MenuItem addContactBtn = null; private MenuItem flipCameraBtn = null; private MenuItem dialPadBtn = null; - private SurfaceView video = null; - private SurfaceView videoPreview = null; - ViewSwitcher mSecuritySwitch; - private TextView mCallStatusTxt; + @BindView(R.id.camera_preview_surface) + SurfaceView videoPreview = null; - public Callbacks mCallbacks = sDummyCallbacks; + public ConversationCallbacks mCallbacks = sDummyCallbacks; private AudioManager audioManager; - private boolean haveVideo = false; private int videoWidth = -1, videoHeight = -1; private int previewWidth = -1, previewHeight = -1; - private boolean lastVideoSource = true; + private boolean lastVideoSource = true; private Conference mCachedConference = null; - private ViewGroup rootView = null; - private boolean ongoingCall = false; - private EditText mNumeralDialEditText; + private boolean ongoingCall = false; private DisplayManager.DisplayListener displayListener; @@ -130,11 +162,11 @@ public class CallFragment extends Fragment implements CallInterface { Log.i(TAG, "onAttach"); super.onAttach(activity); - if (!(activity instanceof Callbacks)) { + if (!(activity instanceof ConversationCallbacks)) { throw new IllegalStateException("Activity must implement fragment's callbacks."); } - mCallbacks = (Callbacks) activity; + mCallbacks = (ConversationCallbacks) activity; IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(CallManagerCallBack.RECORD_STATE_CHANGED); @@ -201,23 +233,21 @@ public class CallFragment extends Fragment implements CallInterface { } }; } - - setRetainInstance(true); } @Override public void onDestroy() { + super.onDestroy(); Log.i(TAG, "onDestroy"); if (mScreenWakeLock != null && mScreenWakeLock.isHeld()) { mScreenWakeLock.release(); } - super.onDestroy(); } /** * The Activity calling this fragment has to implement this interface */ - public interface Callbacks extends LocalService.Callbacks { + public interface ConversationCallbacks extends LocalService.Callbacks { void startTimer(); void terminateCall(); @@ -229,34 +259,46 @@ public class CallFragment extends Fragment implements CallInterface { ActionBar getSupportActionBar(); } - /** - * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity. - */ - private static class DummyCallbacks extends LocalService.DummyCallbacks implements Callbacks { + private static final ConversationCallbacks sDummyCallbacks = new ConversationCallbacks() { + @Override + public void startTimer() { + //Dummy implementation + } + @Override public void terminateCall() { + //Dummy implementation } @Override public Conference getDisplayedConference() { + //Dummy implementation return null; } @Override public void updateDisplayedConference(Conference c) { + //Dummy implementation } @Override public ActionBar getSupportActionBar() { + //Dummy implementation return null; } @Override - public void startTimer() { + public IDRingService getRemoteService() { + //Dummy implementation + return null; } - } - private static final Callbacks sDummyCallbacks = new DummyCallbacks(); + @Override + public LocalService getService() { + //Dummy implementation + return null; + } + }; public class CallReceiver extends BroadcastReceiver { private final String TAG = CallReceiver.class.getSimpleName(); @@ -267,25 +309,25 @@ public class CallFragment extends Fragment implements CallInterface { if (action.contentEquals(LocalService.ACTION_CONF_UPDATE)) { confUpdate(); } else if (action.contentEquals(DRingService.VIDEO_EVENT)) { - if (video == null) + if (mVideoSurface == null) return; Conference conf = getConference(); if (intent.hasExtra("start")) { - video.setVisibility(View.VISIBLE); + mVideoSurface.setVisibility(View.VISIBLE); videoPreview.setVisibility(View.VISIBLE); } else if (intent.hasExtra("camera")) { previewWidth = intent.getIntExtra("width", 0); previewHeight = intent.getIntExtra("height", 0); } else if (conf != null && conf.getId().equals(intent.getStringExtra("call"))) { - if (video != null) { + if (mVideoSurface != null) { haveVideo = intent.getBooleanExtra("started", false); if (haveVideo) { - video.setVisibility(View.VISIBLE); + mVideoSurface.setVisibility(View.VISIBLE); videoPreview.setVisibility(View.VISIBLE); videoWidth = intent.getIntExtra("width", 0); videoHeight = intent.getIntExtra("height", 0); } else { - video.setVisibility(View.GONE); + mVideoSurface.setVisibility(View.GONE); videoPreview.setVisibility(View.GONE); } } @@ -362,7 +404,7 @@ public class CallFragment extends Fragment implements CallInterface { speakerPhoneBtn.setChecked(speakerPhone); } if (addContactBtn != null) { - SipCall call = (getConference() != null && !getConference().getParticipants().isEmpty()) ? getConference().getParticipants().get(0) : null; + SipCall call = (getConference() != null && !getConference().getParticipants().isEmpty()) ? getFirstParticipant() : null; addContactBtn.setVisible(call != null && null != call.getContact() && call.getContact().isUnknown()); } @@ -384,12 +426,12 @@ public class CallFragment extends Fragment implements CallInterface { Intent intent = new Intent() .setClass(getActivity(), ConversationActivity.class) .setAction(Intent.ACTION_VIEW) - .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, getConference().getParticipants().get(0).getContact().getIds().get(0))); + .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, getFirstParticipant().getContact().getIds().get(0))); intent.putExtra("resuming", true); startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION); break; case R.id.menuitem_addcontact: - startActivityForResult(getConference().getParticipants().get(0).getContact().getAddNumberIntent(), ConversationActivity.REQ_ADD_CONTACT); + startActivityForResult(getFirstParticipant().getContact().getAddNumberIntent(), ConversationActivity.REQ_ADD_CONTACT); break; case R.id.menuitem_speaker: audioManager.setSpeakerphoneOn(!audioManager.isSpeakerphoneOn()); @@ -448,10 +490,10 @@ public class CallFragment extends Fragment implements CallInterface { } Conference c = getConference(); - if (c != null && video != null && c.resumeVideo) { - Log.w(TAG, "Resuming video"); + if (c != null && mVideoSurface != null && c.resumeVideo) { + Log.i(TAG, "Resuming video"); haveVideo = true; - video.setVisibility(View.VISIBLE); + mVideoSurface.setVisibility(View.VISIBLE); videoPreview.setVisibility(View.VISIBLE); c.resumeVideo = false; } @@ -459,8 +501,8 @@ public class CallFragment extends Fragment implements CallInterface { @Override public void onResume() { - Log.w(TAG, "onResume()"); super.onResume(); + Log.i(TAG, "onResume()"); Conference c = getConference(); this.confUpdate(); @@ -476,7 +518,7 @@ public class CallFragment extends Fragment implements CallInterface { if (c.resumeVideo) { Log.w(TAG, "Resuming video"); haveVideo = true; - video.setVisibility(View.VISIBLE); + mVideoSurface.setVisibility(View.VISIBLE); videoPreview.setVisibility(View.VISIBLE); c.resumeVideo = false; } @@ -576,7 +618,7 @@ public class CallFragment extends Fragment implements CallInterface { @Override public void rtcpReportReceived(Conference c, HashMap<String, Integer> stats) { - + // No implementation yet } @Override @@ -589,9 +631,7 @@ public class CallFragment extends Fragment implements CallInterface { Conference c = data.getParcelableExtra("target"); transfer = data.getParcelableExtra("transfer"); try { - mCallbacks.getRemoteService().attendedTransfer(transfer.getCallId(), c.getParticipants().get(0).getCallId()); - } catch (RemoteException e) { e.printStackTrace(); } @@ -616,13 +656,17 @@ public class CallFragment extends Fragment implements CallInterface { } void resetVideoSizes() { - double video_ratio = videoWidth / (double) videoHeight; - double screen_ratio = rootView.getWidth() / (double) rootView.getHeight(); + ViewGroup rootView = (ViewGroup) getView(); + if (rootView == null) + return; + + double videoRatio = videoWidth / (double) videoHeight; + double screenRatio = getView().getWidth() / (double) getView().getHeight(); - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) video.getLayoutParams(); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mVideoSurface.getLayoutParams(); int oldW = params.width; int oldH = params.height; - if (video_ratio >= screen_ratio) { + if (videoRatio >= screenRatio) { params.width = RelativeLayout.LayoutParams.MATCH_PARENT; params.height = (int) (videoHeight * (double) rootView.getWidth() / (double) videoWidth); } else { @@ -632,20 +676,20 @@ public class CallFragment extends Fragment implements CallInterface { if (oldW != params.width || oldH != params.height) { Log.w(TAG, "onLayoutChange " + params.width + " x " + params.height); - video.setLayoutParams(params); + mVideoSurface.setLayoutParams(params); } DisplayMetrics metrics = getResources().getDisplayMetrics(); - FrameLayout.LayoutParams params_preview = (FrameLayout.LayoutParams) videoPreview.getLayoutParams(); - oldW = params_preview.width; - oldH = params_preview.height; - double preview_max_dim = Math.max(previewWidth, previewHeight); - double preview_ratio = metrics.density * 160. / preview_max_dim; - params_preview.width = (int) (previewWidth * preview_ratio); - params_preview.height = (int) (previewHeight * preview_ratio); - if (oldW != params_preview.width || oldH != params_preview.height) { - Log.w(TAG, "onLayoutChange " + params_preview.width + " x " + params_preview.height); - videoPreview.setLayoutParams(params_preview); + FrameLayout.LayoutParams paramsPreview = (FrameLayout.LayoutParams) videoPreview.getLayoutParams(); + oldW = paramsPreview.width; + oldH = paramsPreview.height; + double previewMaxDim = Math.max(previewWidth, previewHeight); + double previewRatio = metrics.density * 160. / previewMaxDim; + paramsPreview.width = (int) (previewWidth * previewRatio); + paramsPreview.height = (int) (previewHeight * previewRatio); + if (oldW != paramsPreview.width || oldH != paramsPreview.height) { + Log.i(TAG, "onLayoutChange " + paramsPreview.width + " x " + paramsPreview.height); + videoPreview.setLayoutParams(paramsPreview); } } @@ -664,9 +708,10 @@ public class CallFragment extends Fragment implements CallInterface { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.i(TAG, "onCreateView"); - rootView = (ViewGroup) inflater.inflate(R.layout.frag_call, container, false); + View rootView = inflater.inflate(R.layout.frag_call, container, false); + + ButterKnife.bind(this, rootView); - mNumeralDialEditText = (EditText) rootView.findViewById(R.id.dialpad_edit_text); mNumeralDialEditText.requestFocus(); mNumeralDialEditText.addTextChangedListener(new TextWatcher() { @Override @@ -694,20 +739,9 @@ public class CallFragment extends Fragment implements CallInterface { } }); - contactBubbleLayout = rootView.findViewById(R.id.contact_bubble_layout); - contactBubbleView = (ImageView) rootView.findViewById(R.id.contact_bubble); - contactBubbleTxt = (TextView) rootView.findViewById(R.id.contact_bubble_txt); - contactBubbleNumTxt = (TextView) rootView.findViewById(R.id.contact_bubble_num_txt); - acceptButton = rootView.findViewById(R.id.call_accept_btn); - refuseButton = rootView.findViewById(R.id.call_refuse_btn); - hangupButton = rootView.findViewById(R.id.call_hangup_btn); - mCallStatusTxt = (TextView) rootView.findViewById(R.id.call_status_txt); - mSecuritySwitch = (ViewSwitcher) rootView.findViewById(R.id.security_switcher); - securityIndicator = rootView.findViewById(R.id.security_indicator); - - video = (SurfaceView) rootView.findViewById(R.id.video_preview_surface); - video.getHolder().setFormat(PixelFormat.RGBA_8888); - video.getHolder().addCallback(new SurfaceHolder.Callback() { + + mVideoSurface.getHolder().setFormat(PixelFormat.RGBA_8888); + mVideoSurface.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { contactBubbleLayout.setVisibility(View.GONE); @@ -755,7 +789,6 @@ public class CallFragment extends Fragment implements CallInterface { } }); - videoPreview = (SurfaceView) rootView.findViewById(R.id.camera_preview_surface); videoPreview.getHolder().setFormat(PixelFormat.RGBA_8888); videoPreview.getHolder().addCallback(new SurfaceHolder.Callback() { @Override @@ -803,6 +836,7 @@ public class CallFragment extends Fragment implements CallInterface { } private void initContactDisplay(final SipCall call) { + CallContact contact = call.getContact(); final String name = contact.getDisplayName(); contactBubbleTxt.setText(name); @@ -812,7 +846,11 @@ public class CallFragment extends Fragment implements CallInterface { contactBubbleNumTxt.setVisibility(View.VISIBLE); contactBubbleNumTxt.setText(call.getNumber()); } + + mPulseAnimation.startRippleAnimation(); + new ContactPictureTask(getActivity(), contactBubbleView, contact).run(); + ActionBar ab = mCallbacks.getSupportActionBar(); ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE); ab.setTitle(name); @@ -823,30 +861,16 @@ public class CallFragment extends Fragment implements CallInterface { mCallbacks.startTimer(); acceptButton.setVisibility(View.GONE); refuseButton.setVisibility(View.GONE); + hangupButton.setVisibility(View.VISIBLE); - final SipCall call = getConference().getParticipants().get(0); - final String call_id = call.getCallId(); + final SipCall call = getFirstParticipant(); initContactDisplay(call); if (getActivity() != null) { getActivity().invalidateOptionsMenu(); } - hangupButton.setVisibility(View.VISIBLE); - hangupButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - try { - mCallbacks.getRemoteService().hangUp(call_id); - mCallbacks.terminateCall(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - }); - contactBubbleLayout.setVisibility(haveVideo ? View.GONE : View.VISIBLE); - updateSecurityDisplay(); } @@ -864,7 +888,7 @@ public class CallFragment extends Fragment implements CallInterface { if (getConference().hasMultipleParticipants()) { //TODO What layout should we put? } else { - final SecureSipCall secured = (SecureSipCall) getConference().getParticipants().get(0); + final SecureSipCall secured = (SecureSipCall) getFirstParticipant(); switch (secured.displayModule()) { case SecureSipCall.DISPLAY_GREEN_LOCK: Log.i(TAG, "DISPLAY_GREEN_LOCK"); @@ -903,17 +927,9 @@ public class CallFragment extends Fragment implements CallInterface { mSecuritySwitch.setVisibility(View.VISIBLE); } - /*protected Bitmap getContactPhoto(CallContact contact, int size) { - if (contact.getPhotoId() > 0) { - return ContactPictureTask.loadContactPhoto(getActivity().getContentResolver(), contact.getId()); - } else { - return ContactPictureTask.decodeSampledBitmapFromResource(getResources(), R.drawable.ic_contact_picture, size, size); - } - }*/ - private void initIncomingCallDisplay() { Log.i(TAG, "Start incoming display"); - final SipCall call = getConference().getParticipants().get(0); + final SipCall call = getFirstParticipant(); if (mCallbacks.getService().getAccount(call.getAccount()).isAutoanswerEnabled()) { try { mCallbacks.getRemoteService().accept(call.getCallId()); @@ -923,32 +939,7 @@ public class CallFragment extends Fragment implements CallInterface { } else { initContactDisplay(call); acceptButton.setVisibility(View.VISIBLE); - acceptButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - acceptButton.setOnClickListener(null); - refuseButton.setOnClickListener(null); - try { - mCallbacks.getRemoteService().accept(call.getCallId()); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - }); refuseButton.setVisibility(View.VISIBLE); - refuseButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - acceptButton.setOnClickListener(null); - refuseButton.setOnClickListener(null); - try { - mCallbacks.getRemoteService().refuse(call.getCallId()); - mCallbacks.terminateCall(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - }); hangupButton.setVisibility(View.GONE); } } @@ -956,51 +947,60 @@ public class CallFragment extends Fragment implements CallInterface { private void initOutGoingCallDisplay() { Log.i(TAG, "Start outgoing display"); - final SipCall call = getConference().getParticipants().get(0); + final SipCall call = getFirstParticipant(); initContactDisplay(call); acceptButton.setVisibility(View.GONE); - refuseButton.setVisibility(View.GONE); - - hangupButton.setVisibility(View.VISIBLE); - hangupButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - try { - mCallbacks.getRemoteService().hangUp(call.getCallId()); - mCallbacks.terminateCall(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - }); - + refuseButton.setVisibility(View.VISIBLE); + hangupButton.setVisibility(View.GONE); } - /* - public void makeTransfer(BubbleContact contact) { - FragmentManager fm = getFragmentManager(); - editName = TransferDFragment.newInstance(); - Bundle b = new Bundle(); - try { - b.putParcelableArrayList("calls", (ArrayList<Conference>) mCallbacks.getRemoteService().getConcurrentCalls()); - b.putParcelable("call_selected", contact.associated_call); - editName.setArguments(b); - editName.setTargetFragment(this, REQUEST_TRANSFER); - editName.show(fm, ""); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - - }*/ - public void updateTime() { if (getConference() != null && !getConference().getParticipants().isEmpty()) { - long duration = System.currentTimeMillis() - getConference().getParticipants().get(0).getTimestampStart(); + long duration = System.currentTimeMillis() - getFirstParticipant().getTimestampStart(); duration = duration / 1000; if (getConference().isOnGoing()) mCallStatusTxt.setText(String.format("%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60)); } + } + @OnClick({R.id.call_hangup_btn, R.id.call_refuse_btn}) + public void hangUpClicked() { + try { + final SipCall call = getFirstParticipant(); + if (call == null) { + return; + } + final String callId = call.getCallId(); + mCallbacks.getRemoteService().hangUp(callId); + mCallbacks.terminateCall(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @OnClick(R.id.call_accept_btn) + public void acceptClicked() { + final SipCall call = getFirstParticipant(); + if (call == null) { + return; + } + try { + mCallbacks.getRemoteService().accept(call.getCallId()); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + /** + * Helper accessor that check nullity or emptiness of components to access first call participant + * @return the first participant or null + */ + @Nullable + private SipCall getFirstParticipant() { + if (getConference() == null || getConference().getParticipants() == null || getConference().getParticipants().isEmpty()) { + return null; + } + return getConference().getParticipants().get(0); } } diff --git a/ring-android/app/src/main/res/layout-land/frag_call.xml b/ring-android/app/src/main/res/layout-land/frag_call.xml new file mode 100644 index 000000000..8fa4aa64e --- /dev/null +++ b/ring-android/app/src/main/res/layout-land/frag_call.xml @@ -0,0 +1,218 @@ +<?xml version="1.0" encoding="utf-8"?><!-- +Copyright (C) 2004-2016 Savoir-faire Linux Inc. + +Author: Adrien Beraud <adrien.beraud@savoirfairelinux.com> + +This program 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. + +This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +--> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".client.CallActivity"> + + <SurfaceView + android:id="@+id/video_preview_surface" + android:layout_width="match_parent" + android:layout_height="32dp" + android:layout_gravity="center" + android:visibility="gone" /> + + <FrameLayout + android:id="@+id/inner_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + + <SurfaceView + android:id="@+id/camera_preview_surface" + android:layout_width="160dp" + android:layout_height="120dp" + android:layout_gravity="bottom|end" + android:layout_margin="8dp" + android:visibility="gone" /> + + <LinearLayout + android:id="@+id/contact_bubble_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:weightSum="100" + android:orientation="horizontal" + android:layout_marginBottom="16dp"> + + <com.skyfishjy.library.RippleBackground + android:id="@+id/ripple_animation" + android:layout_width="0dp" + android:layout_weight="50" + android:layout_height="match_parent" + app:rb_color="@color/white" + app:rb_duration="5000" + app:rb_radius="20dp" + app:rb_rippleAmount="3" + app:rb_scale="6"> + + <ImageView + android:id="@+id/contact_bubble" + android:layout_width="160dp" + android:layout_height="160dp" + android:layout_centerInParent="true" + tools:src="@drawable/ic_contact_picture" /> + </com.skyfishjy.library.RippleBackground> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:gravity="center" + android:layout_weight="50" + android:layout_margin="10dp" + android:orientation="vertical"> + + <TextView + android:id="@+id/contact_bubble_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textColor="@color/text_color_primary_dark" + tools:text="Contact Name" /> + + <TextView + android:id="@+id/contact_bubble_num_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:ellipsize="end" + android:paddingEnd="32dp" + android:paddingStart="32dp" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="@color/text_color_secondary_dark" + tools:text="ring:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" /> + + <TextView + android:id="@+id/call_status_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:textColor="@color/text_color_primary_dark" + android:textSize="16sp" + tools:text="Connecting" /> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="12dp" + android:orientation="horizontal"> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/call_refuse_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:contentDescription="@string/action_call_decline" + android:src="@drawable/ic_call_end_white_24dp" + app:backgroundTint="@color/error_red" + app:elevation="6dp" + app:pressedTranslationZ="12dp" + app:rippleColor="@android:color/white" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/call_accept_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:contentDescription="@string/action_call_accept" + android:src="@drawable/ic_call_white_24dp" + app:backgroundTint="#4caf50" + app:elevation="6dp" + app:pressedTranslationZ="12dp" + app:rippleColor="@android:color/white" /> + </LinearLayout> + + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/imageView" + android:layout_gravity="center_horizontal" /> + + + </LinearLayout> + </LinearLayout> + + <RelativeLayout + android:id="@+id/call_status_bar" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:visibility="visible"> + + <ViewSwitcher + android:id="@+id/security_switcher" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:visibility="gone"> + + <Button + android:id="@+id/confirm_sas" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:textColor="@android:color/white" + android:textSize="12sp" /> + + <ImageView + android:id="@+id/lock_image" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end|center_vertical" /> + </ViewSwitcher> + + <ImageView + android:id="@+id/security_indicator" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:layout_margin="16dp" + android:src="@drawable/ic_lock_white_24dp" + android:tint="#4caf50" + android:visibility="gone" /> + + </RelativeLayout> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/call_hangup_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:layout_margin="28dp" + android:src="@drawable/ic_call_end_white_24dp" + app:backgroundTint="@color/error_red" + app:elevation="6dp" + app:pressedTranslationZ="12dp" + app:rippleColor="@android:color/white" /> + + <EditText + android:id="@+id/dialpad_edit_text" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:ems="10" + android:inputType="phone" + android:visibility="visible" /> + + </FrameLayout> +</FrameLayout> \ No newline at end of file diff --git a/ring-android/app/src/main/res/layout/activity_call_layout.xml b/ring-android/app/src/main/res/layout/activity_call_layout.xml index f12e4435d..cf29ef591 100644 --- a/ring-android/app/src/main/res/layout/activity_call_layout.xml +++ b/ring-android/app/src/main/res/layout/activity_call_layout.xml @@ -20,7 +20,7 @@ along with this program; if not, write to the Free Software <cx.ring.views.FitsWindowsLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/maincalllayout" + android:id="@+id/main_call_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/cardview_dark_background" diff --git a/ring-android/app/src/main/res/layout/frag_call.xml b/ring-android/app/src/main/res/layout/frag_call.xml index 656d3c714..7c9f8c95e 100644 --- a/ring-android/app/src/main/res/layout/frag_call.xml +++ b/ring-android/app/src/main/res/layout/frag_call.xml @@ -44,53 +44,76 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. android:layout_margin="8dp" android:visibility="gone" /> - <LinearLayout + <RelativeLayout android:id="@+id/contact_bubble_layout" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginBottom="16dp" - android:gravity="center_horizontal" - android:orientation="vertical"> + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginBottom="16dp"> + + <com.skyfishjy.library.RippleBackground + android:id="@+id/ripple_animation" + android:layout_width="230dp" + android:layout_height="230dp" + android:layout_centerInParent="true" + app:rb_color="@color/white" + app:rb_duration="5000" + app:rb_radius="20dp" + app:rb_rippleAmount="3" + app:rb_scale="6"> - <ImageView - android:id="@+id/contact_bubble" - android:layout_width="160dp" - android:layout_height="160dp" - android:layout_marginBottom="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" /> - - <TextView - android:id="@+id/contact_bubble_txt" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center_horizontal" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceLarge" - android:textColor="@color/text_color_primary_dark" /> - - <TextView - android:id="@+id/contact_bubble_num_txt" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:ellipsize="middle" - android:gravity="center_horizontal" - android:paddingEnd="8dp" - android:paddingStart="8dp" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="@color/text_color_secondary_dark" /> - - <TextView - android:id="@+id/call_status_txt" - android:layout_width="wrap_content" + <ImageView + android:id="@+id/contact_bubble" + android:layout_width="160dp" + android:layout_height="160dp" + android:layout_centerInParent="true" + tools:src="@drawable/ic_contact_picture" /> + </com.skyfishjy.library.RippleBackground> + + <LinearLayout + android:layout_width="300dp" android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="@color/text_color_primary_dark" - android:textSize="16sp" /> + android:layout_below="@id/ripple_animation" + android:layout_centerHorizontal="true" + android:layout_margin="10dp" + android:orientation="vertical"> - </LinearLayout> + <TextView + android:id="@+id/contact_bubble_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textColor="@color/text_color_primary_dark" + tools:text="Contact Name" /> + + <TextView + android:id="@+id/contact_bubble_num_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:ellipsize="end" + android:paddingEnd="32dp" + android:paddingStart="32dp" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="@color/text_color_secondary_dark" + tools:text="ring:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" /> + + <TextView + android:id="@+id/call_status_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:textColor="@color/text_color_primary_dark" + android:textSize="16sp" + tools:text="Connecting" /> + + </LinearLayout> + + + </RelativeLayout> <LinearLayout android:layout_width="wrap_content" -- GitLab