Call : Manage microphone detection
Change-Id: Ib21105b7e7ca6c19fa11d973b676389908415e4e
diff --git a/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java b/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java
index 9772cd4..e0e369a 100644
--- a/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java
@@ -28,6 +28,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Toast;
import javax.inject.Inject;
@@ -37,9 +38,10 @@
import cx.ring.account.RingAccountCreationFragment;
import cx.ring.application.RingApplication;
import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.model.RingError;
import cx.ring.utils.Log;
-public abstract class BaseFragment<T extends RootPresenter> extends Fragment {
+public abstract class BaseFragment<T extends RootPresenter> extends Fragment implements BaseView {
protected static final String TAG = BaseFragment.class.getSimpleName();
@@ -82,6 +84,20 @@
mUnbinder.unbind();
}
+ public void displayErrorToast(int error) {
+ String errorString;
+ switch (error) {
+ case RingError.NO_MICROPHONE:
+ errorString = getString(R.string.call_error_no_microphone);
+ break;
+ default:
+ errorString = getString(R.string.generic_error);
+ break;
+ }
+
+ Toast.makeText(getActivity(), errorString, Toast.LENGTH_LONG).show();
+ }
+
protected void initPresenter(T presenter) {
}
diff --git a/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java
index d2b4b1a..aa2dfdc 100644
--- a/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java
+++ b/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java
@@ -20,11 +20,13 @@
package cx.ring.services;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.hardware.Camera;
import android.media.AudioManager;
+import android.media.MediaRecorder;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.LongSparseArray;
@@ -32,6 +34,7 @@
import android.view.SurfaceHolder;
import android.view.WindowManager;
+import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Collections;
@@ -86,6 +89,29 @@
setDefaultVideoDevice(Integer.toString(cameraFront));
}
+ public boolean hasMicrophone() {
+ PackageManager pm = mContext.getPackageManager();
+ boolean hasMicrophone = pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
+
+ if (!hasMicrophone) {
+ MediaRecorder recorder = new MediaRecorder();
+ recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
+ recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
+ recorder.setOutputFile(new File(mContext.getCacheDir(), "MediaUtil#micAvailTestFile").getAbsolutePath());
+ try {
+ recorder.prepare();
+ recorder.start();
+ hasMicrophone = true;
+ } catch (Exception exception) {
+ hasMicrophone = false;
+ }
+ recorder.release();
+ }
+
+ return hasMicrophone;
+ }
+
@Override
public boolean isSpeakerPhoneOn() {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/BaseBrowseFragment.java b/ring-android/app/src/main/java/cx/ring/tv/main/BaseBrowseFragment.java
index 1c933a3..cf07c3d 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/BaseBrowseFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/BaseBrowseFragment.java
@@ -22,12 +22,16 @@
import android.os.Bundle;
import android.support.v17.leanback.app.BrowseFragment;
import android.view.View;
+import android.widget.Toast;
import javax.inject.Inject;
+import cx.ring.R;
+import cx.ring.model.RingError;
+import cx.ring.mvp.BaseView;
import cx.ring.mvp.RootPresenter;
-public class BaseBrowseFragment<T extends RootPresenter> extends BrowseFragment {
+public class BaseBrowseFragment<T extends RootPresenter> extends BrowseFragment implements BaseView {
protected static final String TAG = BaseBrowseFragment.class.getSimpleName();
@@ -49,6 +53,20 @@
presenter.unbindView();
}
+ public void displayErrorToast(int error) {
+ String errorString;
+ switch (error) {
+ case RingError.NO_MICROPHONE:
+ errorString = getString(R.string.call_error_no_microphone);
+ break;
+ default:
+ errorString = getString(R.string.generic_error);
+ break;
+ }
+
+ Toast.makeText(getActivity(), errorString, Toast.LENGTH_LONG).show();
+ }
+
protected void initPresenter(T presenter) {
}
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java b/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java
index 2b828fb..1b19fbd 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java
@@ -30,11 +30,13 @@
import cx.ring.model.Account;
import cx.ring.model.CallContact;
import cx.ring.model.Conversation;
+import cx.ring.model.RingError;
import cx.ring.model.ServiceEvent;
import cx.ring.model.Uri;
import cx.ring.mvp.RootPresenter;
import cx.ring.services.AccountService;
import cx.ring.services.ContactService;
+import cx.ring.services.HardwareService;
import cx.ring.services.PresenceService;
import cx.ring.tv.model.TVListViewModel;
import cx.ring.utils.Observable;
@@ -46,27 +48,25 @@
private static final String TAG = MainPresenter.class.getSimpleName();
private AccountService mAccountService;
-
private ConversationFacade mConversationFacade;
-
private ContactService mContactService;
-
private PresenceService mPresenceService;
-
+ private HardwareService mHardwareService;
private ExecutorService mExecutor;
-
private ArrayList<Conversation> mConversations;
@Inject
public MainPresenter(AccountService accountService,
ContactService contactService,
PresenceService presenceService,
+ HardwareService hardwareService,
@Named("ApplicationExecutor") ExecutorService executor,
ConversationFacade conversationfacade) {
mAccountService = accountService;
mContactService = contactService;
mPresenceService = presenceService;
mConversationFacade = conversationfacade;
+ this.mHardwareService = hardwareService;
mExecutor = executor;
mConversations = new ArrayList<>();
}
@@ -154,6 +154,11 @@
}
public void contactClicked(TVListViewModel item) {
+ if (!mHardwareService.hasMicrophone()) {
+ getView().displayErrorToast(RingError.NO_MICROPHONE);
+ return;
+ }
+
String accountID = mAccountService.getCurrentAccount().getAccountID();
String ringID = item.getCallContact().getPhones().get(0).getNumber().toString();
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java b/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java
index 56ce466..fdf25f1 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java
@@ -21,6 +21,7 @@
import java.util.ArrayList;
+import cx.ring.model.RingError;
import cx.ring.tv.model.TVListViewModel;
public interface MainView {
@@ -33,6 +34,8 @@
void callContact(String accountID, String ringID);
+ void displayErrorToast(int error);
+
void displayAccountInfos(String address);
void showExportDialog(String pAccountID);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/search/BaseSearchFragment.java b/ring-android/app/src/main/java/cx/ring/tv/search/BaseSearchFragment.java
index d4a15ec..1ab83e9 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/search/BaseSearchFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/search/BaseSearchFragment.java
@@ -21,13 +21,18 @@
import android.os.Bundle;
import android.view.View;
+import android.widget.Toast;
import javax.inject.Inject;
+import cx.ring.R;
+import cx.ring.model.RingError;
+import cx.ring.mvp.BaseView;
import cx.ring.mvp.RootPresenter;
import cx.ring.utils.Log;
-public class BaseSearchFragment<T extends RootPresenter> extends android.support.v17.leanback.app.SearchFragment {
+public class BaseSearchFragment<T extends RootPresenter> extends android.support.v17.leanback.app.SearchFragment
+ implements BaseView {
protected static final String TAG = BaseSearchFragment.class.getSimpleName();
@@ -50,6 +55,21 @@
presenter.unbindView();
}
+ @Override
+ public void displayErrorToast(int error) {
+ String errorString;
+ switch (error) {
+ case RingError.NO_MICROPHONE:
+ errorString = getString(R.string.call_error_no_microphone);
+ break;
+ default:
+ errorString = getString(R.string.generic_error);
+ break;
+ }
+
+ Toast.makeText(getActivity(), errorString, Toast.LENGTH_LONG).show();
+ }
+
protected void initPresenter(T presenter) {
}
diff --git a/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchPresenter.java b/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchPresenter.java
index d9c1167..dff9407 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchPresenter.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchPresenter.java
@@ -23,10 +23,12 @@
import cx.ring.model.Account;
import cx.ring.model.CallContact;
+import cx.ring.model.RingError;
import cx.ring.model.ServiceEvent;
import cx.ring.model.Uri;
import cx.ring.mvp.RootPresenter;
import cx.ring.services.AccountService;
+import cx.ring.services.HardwareService;
import cx.ring.utils.NameLookupInputHandler;
import cx.ring.utils.Observable;
import cx.ring.utils.Observer;
@@ -36,15 +38,18 @@
private static final String TAG = RingSearchPresenter.class.getSimpleName();
- AccountService mAccountService;
+ private AccountService mAccountService;
+ private HardwareService mHardwareService;
private NameLookupInputHandler mNameLookupInputHandler;
private String mLastBlockchainQuery = null;
private CallContact mCallContact;
@Inject
- public RingSearchPresenter(AccountService accountService) {
+ public RingSearchPresenter(AccountService accountService,
+ HardwareService hardwareService) {
this.mAccountService = accountService;
+ this.mHardwareService = hardwareService;
}
@Override
@@ -145,6 +150,11 @@
}
public void contactClicked(CallContact contact) {
+ if (!mHardwareService.hasMicrophone()) {
+ getView().displayErrorToast(RingError.NO_MICROPHONE);
+ return;
+ }
+
getView().startCall(mAccountService.getCurrentAccount().getAccountID(), contact.getPhones().get(0).getNumber().toString());
}
}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchView.java b/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchView.java
index c0dbd58..9c8c100 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchView.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchView.java
@@ -20,7 +20,7 @@
package cx.ring.tv.search;
import cx.ring.model.CallContact;
-import cx.ring.model.Uri;
+import cx.ring.model.RingError;
public interface RingSearchView {
@@ -28,5 +28,7 @@
void clearSearch();
+ void displayErrorToast(int error);
+
void startCall(String accountID, String number);
}
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index 7418ee5..e57557b 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -214,4 +214,6 @@
<string name="gallery_error_title">No Gallery app found</string>
<string name="gallery_error_message">No application found on device to open Gallery</string>
+ <string name="generic_error">An unknown error occurred</string>
+
</resources>
diff --git a/ring-android/app/src/main/res/values/strings_call.xml b/ring-android/app/src/main/res/values/strings_call.xml
index 49d4d86..59502a9 100644
--- a/ring-android/app/src/main/res/values/strings_call.xml
+++ b/ring-android/app/src/main/res/values/strings_call.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2004-2016 Savoir-faire Linux Inc.
Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
@@ -21,6 +20,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-->
<resources>
+ <!-- Call error -->
+ <string name="call_error_no_microphone">Call canceled. No microphone detected.</string>
+
<!-- SipCalls -->
<string name="call_human_state_searching">Searching</string>
<string name="call_human_state_incoming">Incoming</string>