Switch RedPhone view<->service interaction to use event bus

Fixes #4234
// FREEBIE
master
Moxie Marlinspike 2015-11-02 14:32:02 -08:00
parent 3e798a9863
commit 5b6f49c993
12 changed files with 218 additions and 274 deletions

View File

@ -2,4 +2,7 @@
-keepattributes SourceFile,LineNumberTable
-keep class org.whispersystems.** { *; }
-keep class org.thoughtcrime.securesms.** { *; }
-keepclassmembers class ** {
public void onEvent*(**);
}

View File

@ -21,34 +21,32 @@ package org.thoughtcrime.redphone;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
import com.afollestad.materialdialogs.AlertDialogWrapper;
import org.thoughtcrime.redphone.crypto.zrtp.SASInfo;
import org.thoughtcrime.redphone.ui.CallControls;
import org.thoughtcrime.redphone.ui.CallScreen;
import org.thoughtcrime.redphone.util.AudioUtils;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.events.RedPhoneEvent;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import de.greenrobot.event.EventBus;
/**
* The main UI class for RedPhone. Most of the heavy lifting is
* done by RedPhoneService, so this activity is mostly responsible
@ -62,40 +60,9 @@ public class RedPhone extends Activity {
private static final String TAG = RedPhone.class.getSimpleName();
private static final int REMOTE_TERMINATE = 0;
private static final int LOCAL_TERMINATE = 1;
public static final int STATE_IDLE = 0;
public static final int STATE_RINGING = 2;
public static final int STATE_DIALING = 3;
public static final int STATE_ANSWERING = 4;
public static final int STATE_CONNECTED = 5;
private static final int STANDARD_DELAY_FINISH = 3000;
private static final int STANDARD_DELAY_FINISH = 1000;
public static final int BUSY_SIGNAL_DELAY_FINISH = 5500;
public static final int HANDLE_CALL_CONNECTED = 0;
public static final int HANDLE_WAITING_FOR_RESPONDER = 1;
public static final int HANDLE_SERVER_FAILURE = 2;
public static final int HANDLE_PERFORMING_HANDSHAKE = 3;
public static final int HANDLE_HANDSHAKE_FAILED = 4;
public static final int HANDLE_CONNECTING_TO_INITIATOR = 5;
public static final int HANDLE_CALL_DISCONNECTED = 6;
public static final int HANDLE_CALL_RINGING = 7;
public static final int HANDLE_SERVER_MESSAGE = 9;
public static final int HANDLE_RECIPIENT_UNAVAILABLE = 10;
public static final int HANDLE_INCOMING_CALL = 11;
public static final int HANDLE_OUTGOING_CALL = 12;
public static final int HANDLE_CALL_BUSY = 13;
public static final int HANDLE_LOGIN_FAILED = 14;
public static final int HANDLE_CLIENT_FAILURE = 15;
public static final int HANDLE_DEBUG_INFO = 16;
public static final int HANDLE_NO_SUCH_USER = 17;
private final Handler callStateHandler = new CallStateHandler();
private int state;
private RedPhoneService redPhoneService;
private CallScreen callScreen;
private BroadcastReceiver bluetoothStateReceiver;
@ -118,7 +85,7 @@ public class RedPhone extends Activity {
super.onResume();
initializeScreenshotSecurity();
initializeServiceBinding();
EventBus.getDefault().registerSticky(this);
registerBluetoothReceiver();
}
@ -127,7 +94,7 @@ public class RedPhone extends Activity {
public void onPause() {
super.onPause();
unbindService(serviceConnection);
EventBus.getDefault().unregister(this);
unregisterReceiver(bluetoothStateReceiver);
}
@ -136,12 +103,6 @@ public class RedPhone extends Activity {
super.onConfigurationChanged(newConfiguration);
}
private void initializeServiceBinding() {
Log.w(TAG, "Binding to RedPhoneService...");
Intent bindIntent = new Intent(this, RedPhoneService.class);
bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private void initializeScreenshotSecurity() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH &&
TextSecurePreferences.isScreenSecurityEnabled(this))
@ -154,8 +115,6 @@ public class RedPhone extends Activity {
private void initializeResources() {
callScreen = (CallScreen)findViewById(R.id.callScreen);
state = STATE_IDLE;
callScreen.setHangupButtonListener(new HangupButtonListener());
callScreen.setIncomingCallActionListener(new IncomingCallActionListener());
callScreen.setMuteButtonListener(new MuteButtonListener());
@ -170,140 +129,123 @@ public class RedPhone extends Activity {
}
private void handleAnswerCall() {
state = STATE_ANSWERING;
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(org.thoughtcrime.securesms.R.string.RedPhone_answering));
RedPhoneEvent event = EventBus.getDefault().getStickyEvent(RedPhoneEvent.class);
Intent intent = new Intent(this, RedPhoneService.class);
intent.setAction(RedPhoneService.ACTION_ANSWER_CALL);
startService(intent);
if (event != null) {
callScreen.setActiveCall(event.getRecipient(), getString(org.thoughtcrime.securesms.R.string.RedPhone_answering));
Intent intent = new Intent(this, RedPhoneService.class);
intent.setAction(RedPhoneService.ACTION_ANSWER_CALL);
startService(intent);
}
}
private void handleDenyCall() {
state = STATE_IDLE;
RedPhoneEvent event = EventBus.getDefault().getStickyEvent(RedPhoneEvent.class);
Intent intent = new Intent(this, RedPhoneService.class);
intent.setAction(RedPhoneService.ACTION_DENY_CALL);
startService(intent);
if (event != null) {
Intent intent = new Intent(this, RedPhoneService.class);
intent.setAction(RedPhoneService.ACTION_DENY_CALL);
startService(intent);
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(org.thoughtcrime.securesms.R.string.RedPhone_ending_call));
delayedFinish();
callScreen.setActiveCall(event.getRecipient(), getString(org.thoughtcrime.securesms.R.string.RedPhone_ending_call));
delayedFinish();
}
}
private void handleIncomingCall(Recipient recipient) {
state = STATE_RINGING;
callScreen.setIncomingCall(redPhoneService.getRecipient());
private void handleIncomingCall(@NonNull RedPhoneEvent event) {
callScreen.setIncomingCall(event.getRecipient());
}
private void handleOutgoingCall(Recipient recipient) {
state = STATE_DIALING;
callScreen.setActiveCall(recipient, getString(org.thoughtcrime.securesms.R.string.RedPhone_dialing));
private void handleOutgoingCall(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(org.thoughtcrime.securesms.R.string.RedPhone_dialing));
}
private void handleTerminate( int terminationType ) {
private void handleTerminate(@NonNull Recipient recipient /*, int terminationType */) {
Log.w(TAG, "handleTerminate called");
Log.w(TAG, "Termination Stack:", new Exception());
if( state == STATE_DIALING ) {
if (terminationType == LOCAL_TERMINATE) {
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(org.thoughtcrime.securesms.R.string.RedPhone_canceling_call));
} else {
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_call_rejected));
}
} else if (state != STATE_IDLE) {
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_ending_call));
}
callScreen.setActiveCall(recipient, getString(R.string.RedPhone_ending_call));
state = STATE_IDLE;
delayedFinish();
}
private void handleCallRinging() {
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_ringing));
private void handleCallRinging(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_ringing));
}
private void handleCallBusy() {
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_busy));
private void handleCallBusy(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_busy));
state = STATE_IDLE;
delayedFinish(BUSY_SIGNAL_DELAY_FINISH);
}
private void handleCallConnected(SASInfo sas) {
private void handleCallConnected(@NonNull RedPhoneEvent event) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES);
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_connected), sas);
state = STATE_CONNECTED;
redPhoneService.notifyCallConnectionUIUpdateComplete();
callScreen.setActiveCall(event.getRecipient(),
getString(R.string.RedPhone_connected),
event.getExtra());
}
private void handleDebugInfo( String info ) {
// debugCard.setInfo( info );
private void handleConnectingToInitiator(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_connecting));
}
private void handleConnectingToInitiator() {
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_connecting));
}
private void handleHandshakeFailed() {
state = STATE_IDLE;
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_handshake_failed));
private void handleHandshakeFailed(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_handshake_failed));
delayedFinish();
}
private void handleRecipientUnavailable() {
state = STATE_IDLE;
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_recipient_unavailable));
private void handleRecipientUnavailable(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_recipient_unavailable));
delayedFinish();
}
private void handlePerformingHandshake() {
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_performing_handshake));
private void handlePerformingHandshake(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_performing_handshake));
}
private void handleServerFailure() {
state = STATE_IDLE;
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_network_failed));
private void handleServerFailure(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_network_failed));
delayedFinish();
}
private void handleClientFailure(String msg) {
state = STATE_IDLE;
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_client_failed));
if( msg != null && !isFinishing() ) {
private void handleClientFailure(final @NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_client_failed));
if( event.getExtra() != null && !isFinishing() ) {
AlertDialog.Builder ad = new AlertDialog.Builder(this);
ad.setTitle(R.string.RedPhone_fatal_error);
ad.setMessage(msg);
ad.setMessage(event.getExtra());
ad.setCancelable(false);
ad.setPositiveButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int arg) {
RedPhone.this.handleTerminate(LOCAL_TERMINATE);
RedPhone.this.handleTerminate(event.getRecipient());
}
});
ad.show();
}
}
private void handleLoginFailed() {
state = STATE_IDLE;
callScreen.setActiveCall(redPhoneService.getRecipient(), getString(R.string.RedPhone_login_failed));
private void handleLoginFailed(@NonNull RedPhoneEvent event) {
callScreen.setActiveCall(event.getRecipient(), getString(R.string.RedPhone_login_failed));
delayedFinish();
}
private void handleServerMessage(String message) {
private void handleServerMessage(final @NonNull RedPhoneEvent event) {
if( isFinishing() ) return; //we're already shutting down, this might crash
AlertDialog.Builder ad = new AlertDialog.Builder(this);
ad.setTitle(R.string.RedPhone_message_from_the_server);
ad.setMessage(message);
ad.setMessage(event.getExtra());
ad.setCancelable(false);
ad.setPositiveButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int arg) {
RedPhone.this.handleTerminate(LOCAL_TERMINATE);
RedPhone.this.handleTerminate(event.getRecipient());
}
});
ad.show();
}
private void handleNoSuchUser(final Recipient recipient) {
private void handleNoSuchUser(final @NonNull RedPhoneEvent event) {
if (isFinishing()) return; // XXX Stuart added this check above, not sure why, so I'm repeating in ignorance. - moxie
AlertDialogWrapper.Builder dialog = new AlertDialogWrapper.Builder(this);
dialog.setTitle(R.string.RedPhone_number_not_registered);
@ -313,13 +255,13 @@ public class RedPhone extends Activity {
dialog.setPositiveButton(R.string.RedPhone_got_it, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
RedPhone.this.handleTerminate(LOCAL_TERMINATE);
RedPhone.this.handleTerminate(event.getRecipient());
}
});
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
RedPhone.this.handleTerminate(LOCAL_TERMINATE);
RedPhone.this.handleTerminate(event.getRecipient());
}
});
dialog.show();
@ -330,35 +272,33 @@ public class RedPhone extends Activity {
}
private void delayedFinish(int delayMillis) {
callStateHandler.postDelayed(new Runnable() {
public void run() {
RedPhone.this.finish();
}}, delayMillis);
callScreen.postDelayed(new Runnable() {
public void run() {
RedPhone.this.finish();
}
}, delayMillis);
}
private class CallStateHandler extends Handler {
@Override
public void handleMessage(Message message) {
Log.w(TAG, "Got message from service: " + message.what);
switch (message.what) {
case HANDLE_CALL_CONNECTED: handleCallConnected((SASInfo)message.obj); break;
case HANDLE_SERVER_FAILURE: handleServerFailure(); break;
case HANDLE_PERFORMING_HANDSHAKE: handlePerformingHandshake(); break;
case HANDLE_HANDSHAKE_FAILED: handleHandshakeFailed(); break;
case HANDLE_CONNECTING_TO_INITIATOR: handleConnectingToInitiator(); break;
case HANDLE_CALL_RINGING: handleCallRinging(); break;
case HANDLE_CALL_DISCONNECTED: handleTerminate( REMOTE_TERMINATE ); break;
case HANDLE_SERVER_MESSAGE: handleServerMessage((String)message.obj); break;
case HANDLE_NO_SUCH_USER: handleNoSuchUser((Recipient)message.obj); break;
case HANDLE_RECIPIENT_UNAVAILABLE: handleRecipientUnavailable(); break;
case HANDLE_INCOMING_CALL: handleIncomingCall((Recipient)message.obj); break;
case HANDLE_OUTGOING_CALL: handleOutgoingCall((Recipient)message.obj); break;
case HANDLE_CALL_BUSY: handleCallBusy(); break;
case HANDLE_LOGIN_FAILED: handleLoginFailed(); break;
case HANDLE_CLIENT_FAILURE: handleClientFailure((String)message.obj); break;
case HANDLE_DEBUG_INFO: handleDebugInfo((String)message.obj); break;
}
@SuppressWarnings("unused")
public void onEventMainThread(final RedPhoneEvent event) {
Log.w(TAG, "Got message from service: " + event.getType());
switch (event.getType()) {
case CALL_CONNECTED: handleCallConnected(event); break;
case SERVER_FAILURE: handleServerFailure(event); break;
case PERFORMING_HANDSHAKE: handlePerformingHandshake(event); break;
case HANDSHAKE_FAILED: handleHandshakeFailed(event); break;
case CONNECTING_TO_INITIATOR: handleConnectingToInitiator(event); break;
case CALL_RINGING: handleCallRinging(event); break;
case CALL_DISCONNECTED: handleTerminate(event.getRecipient()); break;
case SERVER_MESSAGE: handleServerMessage(event); break;
case NO_SUCH_USER: handleNoSuchUser(event); break;
case RECIPIENT_UNAVAILABLE: handleRecipientUnavailable(event); break;
case INCOMING_CALL: handleIncomingCall(event); break;
case OUTGOING_CALL: handleOutgoingCall(event); break;
case CALL_BUSY: handleCallBusy(event); break;
case LOGIN_FAILED: handleLoginFailed(event); break;
case CLIENT_FAILURE: handleClientFailure(event); break;
}
}
@ -369,7 +309,11 @@ public class RedPhone extends Activity {
intent.setAction(RedPhoneService.ACTION_HANGUP_CALL);
startService(intent);
RedPhone.this.handleTerminate(LOCAL_TERMINATE);
RedPhoneEvent event = EventBus.getDefault().getStickyEvent(RedPhoneEvent.class);
if (event != null) {
RedPhone.this.handleTerminate(event.getRecipient());
}
}
}
@ -418,30 +362,11 @@ public class RedPhone extends Activity {
public void onAcceptClick() {
RedPhone.this.handleAnswerCall();
}
@Override
public void onDenyClick() {
RedPhone.this.handleDenyCall();
}
}
private ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
RedPhone.this.redPhoneService = ((RedPhoneService.RedPhoneServiceBinder)service).getService();
redPhoneService.setCallStateHandler(callStateHandler);
Recipient recipient = redPhoneService.getRecipient();
switch (redPhoneService.getState()) {
case STATE_IDLE: callScreen.reset(); break;
case STATE_RINGING: handleIncomingCall(recipient); break;
case STATE_DIALING: handleOutgoingCall(recipient); break;
case STATE_ANSWERING: handleAnswerCall(); break;
case STATE_CONNECTED: handleCallConnected(redPhoneService.getCurrentCallSAS()); break;
}
}
public void onServiceDisconnected(ComponentName name) {
redPhoneService.setCallStateHandler(null);
}
};
}

View File

@ -22,12 +22,13 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import org.thoughtcrime.redphone.audio.IncomingRinger;
@ -47,6 +48,8 @@ import org.thoughtcrime.redphone.signaling.SignalingSocket;
import org.thoughtcrime.redphone.ui.NotificationBarManager;
import org.thoughtcrime.redphone.util.UncaughtExceptionHandlerManager;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.events.RedPhoneEvent;
import org.thoughtcrime.securesms.events.RedPhoneEvent.Type;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
@ -57,8 +60,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.LinkedList;
import java.util.List;
import de.greenrobot.event.EventBus;
/**
* The major entry point for all of the heavy lifting associated with
@ -73,6 +76,12 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
private static final String TAG = RedPhoneService.class.getSimpleName();
private static final int STATE_IDLE = 0;
private static final int STATE_RINGING = 2;
private static final int STATE_DIALING = 3;
private static final int STATE_ANSWERING = 4;
private static final int STATE_CONNECTED = 5;
public static final String EXTRA_REMOTE_NUMBER = "remote_number";
public static final String EXTRA_SESSION_DESCRIPTOR = "session_descriptor";
public static final String EXTRA_MUTE = "mute_value";
@ -84,8 +93,6 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
public static final String ACTION_HANGUP_CALL = "org.thoughtcrime.redphone.RedPhoneService.HANGUP";
public static final String ACTION_SET_MUTE = "org.thoughtcrime.redphone.RedPhoneService.SET_MUTE";
private final List<Message> bufferedEvents = new LinkedList<>();
private final IBinder binder = new RedPhoneServiceBinder();
private final Handler serviceHandler = new Handler();
private OutgoingRinger outgoingRinger;
@ -98,7 +105,6 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
private LockManager lockManager;
private UncaughtExceptionHandlerManager uncaughtExceptionHandlerManager;
private Handler handler;
private IncomingPstnCallListener pstnCallListener;
@Override
@ -119,7 +125,7 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
@Override
public IBinder onBind(Intent intent) {
return binder;
return null;
}
@Override
@ -155,7 +161,7 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
}
private void initializeResources() {
this.state = RedPhone.STATE_IDLE;
this.state = STATE_IDLE;
this.zid = getZID();
this.lockManager = new LockManager(this);
}
@ -173,7 +179,7 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
SessionDescriptor session = intent.getParcelableExtra(EXTRA_SESSION_DESCRIPTOR);
remoteNumber = intent.getStringExtra(EXTRA_REMOTE_NUMBER);
state = RedPhone.STATE_RINGING;
state = STATE_RINGING;
lockManager.updatePhoneState(LockManager.PhoneState.PROCESSING);
this.currentCallManager = new ResponderCallManager(this, this, remoteNumber, localNumber,
@ -190,9 +196,9 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
if (remoteNumber == null || remoteNumber.length() == 0)
return;
sendMessage(RedPhone.HANDLE_OUTGOING_CALL, getRecipient());
sendMessage(Type.OUTGOING_CALL, getRecipient(), null);
state = RedPhone.STATE_DIALING;
state = STATE_DIALING;
lockManager.updatePhoneState(LockManager.PhoneState.INTERACTIVE);
this.currentCallManager = new InitiatingCallManager(this, this, localNumber, password,
remoteNumber, zid);
@ -234,7 +240,7 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
}
private void handleAnswerCall(Intent intent) {
state = RedPhone.STATE_ANSWERING;
state = STATE_ANSWERING;
incomingRinger.stop();
DatabaseFactory.getSmsDatabase(this).insertReceivedCall(remoteNumber);
if (currentCallManager != null) {
@ -243,7 +249,7 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
}
private void handleDenyCall(Intent intent) {
state = RedPhone.STATE_IDLE;
state = STATE_IDLE;
incomingRinger.stop();
DatabaseFactory.getSmsDatabase(this).insertMissedCall(remoteNumber);
if(currentCallManager != null) {
@ -266,12 +272,12 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
private boolean isBusy() {
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
return ((currentCallManager != null && state != RedPhone.STATE_IDLE) ||
return ((currentCallManager != null && state != STATE_IDLE) ||
telephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE);
}
private boolean isIdle() {
return state == RedPhone.STATE_IDLE;
return state == STATE_IDLE;
}
private void shutdownAudio() {
@ -283,15 +289,9 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
return state;
}
public SASInfo getCurrentCallSAS() {
if (currentCallManager != null)
return currentCallManager.getSasInfo();
else
return null;
}
public Recipient getRecipient() {
if (remoteNumber != null) {
public @NonNull Recipient getRecipient() {
if (!TextUtils.isEmpty(remoteNumber)) {
//noinspection ConstantConditions
return RecipientFactory.getRecipientsFromString(this, remoteNumber, true)
.getPrimaryRecipient();
} else {
@ -351,22 +351,10 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
shutdownAudio();
state = RedPhone.STATE_IDLE;
state = STATE_IDLE;
lockManager.updatePhoneState(LockManager.PhoneState.IDLE);
}
public void setCallStateHandler(Handler handler) {
this.handler = handler;
if (handler != null) {
for (Message message : bufferedEvents) {
handler.sendMessage(message);
}
bufferedEvents.clear();
}
}
///////// CallStateListener Implementation
public void notifyCallStale() {
@ -377,7 +365,7 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
public void notifyCallFresh() {
Log.w(TAG, "Good call, time to ring and display call card...");
sendMessage(RedPhone.HANDLE_INCOMING_CALL, getRecipient());
sendMessage(Type.INCOMING_CALL, getRecipient(), null);
lockManager.updatePhoneState(LockManager.PhoneState.INTERACTIVE);
@ -389,7 +377,8 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
public void notifyBusy() {
Log.w("RedPhoneService", "Got busy signal from responder!");
sendMessage(RedPhone.HANDLE_CALL_BUSY, null);
sendMessage(Type.CALL_BUSY, getRecipient(), null);
outgoingRinger.playBusy();
serviceHandler.postDelayed(new Runnable() {
@Override
@ -401,124 +390,103 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
public void notifyCallRinging() {
outgoingRinger.playRing();
sendMessage(RedPhone.HANDLE_CALL_RINGING, null);
sendMessage(Type.CALL_RINGING, getRecipient(), null);
}
public void notifyCallConnected(SASInfo sas) {
outgoingRinger.playComplete();
lockManager.updatePhoneState(LockManager.PhoneState.IN_CALL);
state = RedPhone.STATE_CONNECTED;
synchronized( this ) {
sendMessage(RedPhone.HANDLE_CALL_CONNECTED, sas);
try {
wait();
} catch (InterruptedException e) {
throw new AssertionError( "Wait interrupted in RedPhoneService" );
}
}
}
public void notifyCallConnectionUIUpdateComplete() {
synchronized( this ) {
this.notify();
}
}
public void notifyDebugInfo(String info) {
sendMessage(RedPhone.HANDLE_DEBUG_INFO, info);
state = STATE_CONNECTED;
sendMessage(Type.CALL_CONNECTED, getRecipient(), sas.getSasText());
}
public void notifyConnectingtoInitiator() {
sendMessage(RedPhone.HANDLE_CONNECTING_TO_INITIATOR, null);
sendMessage(Type.CONNECTING_TO_INITIATOR, getRecipient(), null);
}
public void notifyCallDisconnected() {
if (state == RedPhone.STATE_RINGING)
if (state == STATE_RINGING)
handleMissedCall(remoteNumber);
sendMessage(RedPhone.HANDLE_CALL_DISCONNECTED, null);
sendMessage(Type.CALL_DISCONNECTED, getRecipient(), null);
this.terminate();
}
public void notifyHandshakeFailed() {
state = RedPhone.STATE_IDLE;
state = STATE_IDLE;
outgoingRinger.playFailure();
sendMessage(RedPhone.HANDLE_HANDSHAKE_FAILED, null);
sendMessage(Type.HANDSHAKE_FAILED, getRecipient(), null);
this.terminate();
}
public void notifyRecipientUnavailable() {
state = RedPhone.STATE_IDLE;
state = STATE_IDLE;
outgoingRinger.playFailure();
sendMessage(RedPhone.HANDLE_RECIPIENT_UNAVAILABLE, null);
sendMessage(Type.RECIPIENT_UNAVAILABLE, getRecipient(), null);
this.terminate();
}
public void notifyPerformingHandshake() {
outgoingRinger.playHandshake();
sendMessage(RedPhone.HANDLE_PERFORMING_HANDSHAKE, null);
sendMessage(Type.PERFORMING_HANDSHAKE, getRecipient(), null);
}
public void notifyServerFailure() {
if (state == RedPhone.STATE_RINGING)
if (state == STATE_RINGING)
handleMissedCall(remoteNumber);
state = RedPhone.STATE_IDLE;
state = STATE_IDLE;
outgoingRinger.playFailure();
sendMessage(RedPhone.HANDLE_SERVER_FAILURE, null);
sendMessage(Type.SERVER_FAILURE, getRecipient(), null);
this.terminate();
}
public void notifyClientFailure() {
if (state == RedPhone.STATE_RINGING)
if (state == STATE_RINGING)
handleMissedCall(remoteNumber);
state = RedPhone.STATE_IDLE;
state = STATE_IDLE;
outgoingRinger.playFailure();
sendMessage(RedPhone.HANDLE_CLIENT_FAILURE, null);
sendMessage(Type.CLIENT_FAILURE, getRecipient(), null);
this.terminate();
}
public void notifyLoginFailed() {
if (state == RedPhone.STATE_RINGING)
if (state == STATE_RINGING)
handleMissedCall(remoteNumber);
state = RedPhone.STATE_IDLE;
state = STATE_IDLE;
outgoingRinger.playFailure();
sendMessage(RedPhone.HANDLE_LOGIN_FAILED, null);
sendMessage(Type.LOGIN_FAILED, getRecipient(), null);
this.terminate();
}
public void notifyNoSuchUser() {
sendMessage(RedPhone.HANDLE_NO_SUCH_USER, getRecipient());
sendMessage(Type.NO_SUCH_USER, getRecipient(), null);
this.terminate();
}
public void notifyServerMessage(String message) {
sendMessage(RedPhone.HANDLE_SERVER_MESSAGE, message);
sendMessage(Type.SERVER_MESSAGE, getRecipient(), message);
this.terminate();
}
public void notifyClientError(String msg) {
sendMessage(RedPhone.HANDLE_CLIENT_FAILURE,msg);
sendMessage(Type.CLIENT_FAILURE, getRecipient(), msg);
this.terminate();
}
public void notifyClientError(int messageId) {
notifyClientError(getString(messageId));
}
public void notifyCallConnecting() {
outgoingRinger.playSonar();
}
public void notifyWaitingForResponder() {}
private void sendMessage(int code, Object extra) {
Message message = Message.obtain();
message.what = code;
message.obj = extra;
if (handler != null) handler.sendMessage(message);
else bufferedEvents.add(message);
private void sendMessage(@NonNull Type type,
@NonNull Recipient recipient,
@Nullable String error)
{
EventBus.getDefault().postSticky(new RedPhoneEvent(type, recipient, error));
}
private class IntentRunnable implements Runnable {
@ -533,21 +501,15 @@ public class RedPhoneService extends Service implements CallStateListener, CallS
}
}
public class RedPhoneServiceBinder extends Binder {
public RedPhoneService getService() {
return RedPhoneService.this;
}
}
@Override
public boolean isInCall() {
switch(state) {
case RedPhone.STATE_IDLE:
case STATE_IDLE:
return false;
case RedPhone.STATE_DIALING:
case RedPhone.STATE_RINGING:
case RedPhone.STATE_ANSWERING:
case RedPhone.STATE_CONNECTED:
case STATE_DIALING:
case STATE_RINGING:
case STATE_ANSWERING:
case STATE_CONNECTED:
return true;
default:
Log.e(TAG, "Unhandled call state: " + state);

View File

@ -43,10 +43,8 @@ public interface CallStateListener {
public void notifyRecipientUnavailable();
public void notifyBusy();
public void notifyLoginFailed();
public void notifyDebugInfo(String info);
public void notifyCallStale();
public void notifyCallFresh();
public void notifyClientError(int msgId);
public void notifyClientError(String message);
public void notifyCallConnecting();
}

View File

@ -23,6 +23,7 @@ import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@ -104,9 +105,9 @@ public class CallControls extends RelativeLayout {
sasTextView.setVisibility(View.GONE);
}
public void setActiveCall(SASInfo sas) {
public void setActiveCall(@Nullable String sas) {
setActiveCall();
sasTextView.setText(sas.getSasText());
sasTextView.setText(sas);
sasTextView.setVisibility(View.VISIBLE);
}

View File

@ -18,6 +18,8 @@
package org.thoughtcrime.redphone.ui;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
@ -53,7 +55,7 @@ public class CallScreen extends FrameLayout {
initialize();
}
public void setActiveCall(Recipient personInfo, String message, SASInfo sas) {
public void setActiveCall(@NonNull Recipient personInfo, @NonNull String message, @Nullable String sas) {
callCard.setCard(personInfo, message);
callControls.setActiveCall(sas);
}

View File

@ -21,7 +21,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.jobs.PartProgressEvent;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.util.Util;

View File

@ -22,7 +22,7 @@ import com.pnikosis.materialishprogress.ProgressWheel;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.jobs.PartProgressEvent;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;

View File

@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.jobs;
package org.thoughtcrime.securesms.events;
import android.support.annotation.NonNull;

View File

@ -0,0 +1,51 @@
package org.thoughtcrime.securesms.events;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.thoughtcrime.securesms.recipients.Recipient;
public class RedPhoneEvent {
public enum Type {
CALL_CONNECTED,
WAITING_FOR_RESPONDER,
SERVER_FAILURE,
PERFORMING_HANDSHAKE,
HANDSHAKE_FAILED,
CONNECTING_TO_INITIATOR,
CALL_DISCONNECTED,
CALL_RINGING,
SERVER_MESSAGE,
RECIPIENT_UNAVAILABLE,
INCOMING_CALL,
OUTGOING_CALL,
CALL_BUSY,
LOGIN_FAILED,
CLIENT_FAILURE,
DEBUG_INFO,
NO_SUCH_USER
}
private final @NonNull Type type;
private final @NonNull Recipient recipient;
private final @Nullable String extra;
public RedPhoneEvent(@NonNull Type type, @NonNull Recipient recipient, @Nullable String extra) {
this.type = type;
this.recipient = recipient;
this.extra = extra;
}
public @NonNull Type getType() {
return type;
}
public @NonNull Recipient getRecipient() {
return recipient;
}
public @Nullable String getExtra() {
return extra;
}
}

View File

@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.crypto.MediaKey;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.jobs.requirements.MediaNetworkRequirement;
import org.thoughtcrime.securesms.notifications.MessageNotifier;

View File

@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.TextSecureDirectory;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.notifications.MessageNotifier;