Just a quick question about the Google speech capture inbuilt on most Android devices (not the cloud service) - see the attached image. Is there any way, either programatically or via the settings, to control how long it waits until it asks you to try again? The 'complete silence' fields in the RecognizerIntent don't seem to make any difference. On certain devices it times out very quickly and the user doesn't have enough time to start speaking.
This is the code in my test app:
public void StartSpeechToText(ISpeechResultCallback callback)
{
string rec = global::Android.Content.PM.PackageManager.FeatureMicrophone;
if (rec == "android.hardware.microphone")
{
MainActivity activity = MainActivity.CurrentActivity;
activity.Callback = callback;
var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
//var voiceIntent = new Intent(RecognizerIntent.ActionVoiceSearchHandsFree);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, "Speak now");
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1500);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1500);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 15000);
voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);
activity.StartActivityForResult(voiceIntent, VOICE);
}
}
Related
I've used successfully the ContinuousScan from ZXing for xamarin using mvvmcross, I just press a button in one of my viewmodels and the camera show up. I used a delay between continuous scans I of 4000 to allow the user to read the barcodes at a slow pace. The first time enter to the view model and enter to the scanner, everything works perfect. Then I press back and i have a list with the codes, I press back again and leave the view model. I enter again to the view model and open the scanner and it just barely has focus on a barcode and it scans it two or three times without waiting for the 4000ms delay that originally was set to it. What am i missing here?
public MvxCommand ObtainCommand()
{
return new MvxCommand(delegate
{
if (HandleScanResultEvent != null) HandleScanResultEvent(this, null);
MobileBarcodeScanner.Initialize(Application);
var scanner = new MobileBarcodeScanner();
scanner.UseCustomOverlay = false;
scanner.TopText = Ts.TopTextScanContiniously;
scanner.BottomText = Ts.BottomTextScan;
var opt = new MobileBarcodeScanningOptions();
opt.DelayBetweenContinuousScans = 5000;
//Start scanning
scanner.ScanContinuously(opt, HandleScanResult);
});
}
The Handle result raise an event to the view model with the barcode read.
void HandleScanResult(ZXing.Result r)
{
if (r != null)
{
var opa = new OperationArgument
{
Operation = new Operation
{
Data r.Text,
Format = FromXingFormat(r.BarcodeFormat)
}
};
if (DataObtained != null && !(String.IsNullOrWhiteSpace(r.Text)))
{
DataObtained(this, opa);
}
}
}
the barcode scanner is opened via an mvxCommand assigned to the viewmodel. The posted code is in a class registered as a singleton.
I have a couple questions of how to implement google game services in my app.
First of all, after I checked that the user is signed in and the client is connected, I launch
Intent intent = Games.TurnBasedMultiplayer.getSelectOpponentsIntent(mGoogleApiClient, 1, 1, true);
startActivityForResult(intent, RC_SELECT_PLAYERS);
To show the user a dialog where they can select the opponent.
After I get the result from the activity I execute this code
if (request == RC_SELECT_PLAYERS) {
Log.e(LOG_TAG, "Got RC_SELECT_PLAYERS result intent");
if (response != Activity.RESULT_OK) {
// user canceled
return;
}
// Get the invitee list.
final ArrayList<String> invitees = data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// Get auto-match criteria.
Bundle autoMatchCriteria;
int minAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
TurnBasedMatchConfig turnBasedMatchConfig = TurnBasedMatchConfig.builder()
.addInvitedPlayers(invitees)
.setAutoMatchCriteria(autoMatchCriteria)
.build();
// Create and start the match.
Games.TurnBasedMultiplayer
.createMatch(mGoogleApiClient, turnBasedMatchConfig)
.setResultCallback(new MatchInitiatedCallback());
}
To initiate the match. The problem is, the opponent I challenged doesn't get any notification where he is asked to join the game. So when the user gets a notification to join a game, how can I catch this notification and show the user the appropriate content? Which intent result should I look for?
In my MatchInitiatedCallback I check which turn it is now:
public class MatchInitiatedCallback implements ResultCallback<TurnBasedMultiplayer.InitiateMatchResult> {
private static final String LOG_TAG = "MatchInitiatedCallback";
#Override
public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
// Check if the status code is not success.
Status status = result.getStatus();
if (!status.isSuccess()) {
Log.e(LOG_TAG, "showError() " + status.toString());
//showError(status.getStatusCode());
return;
}
TurnBasedMatch match = result.getMatch();
// If this player is not the first player in this match, continue.
if (match.getData() != null) {
Log.e(LOG_TAG, "Not my turn");
//showTurnUI(match);
return;
}
// Otherwise, this is the first player. Initialize the game state.
//initGame(match);
Log.e(LOG_TAG, "initGame()");
// Let the player take the first turn
//showTurnUI(match);
Log.e(LOG_TAG, "showTurnGui()");
}
}
But this code gets executed even before my opponent selects to join.
Shouldn't he first be able to accept or decline the game?
Can someone please tell me if I'm doing this properly or if this is supposed to be like this? If not, how should it be implemented correctly?
EDIT: I took all this code from the documentation. It does show some code samples of how to implement things, but not of how the code all comes together and the order in which things should be executed, or how to handle notifications and such.
Yes, it is supposed to work like this. You must take a turn before the opponent actually receives the invitation. In fact, if you invite several opponents, each of them will have to accept the invitation and take a turn before the next opponent is invited, meaning it can take quite a while before you know whether you actually got a match going.
To avoid asking the users to take turns during the invitation phase, your program can take a dummy turn for each user to pass the invitation to the next user. When all users have joined you can start to take real turns.
My Android app uses the Remote Display API to cast video to the user's Cast-enabled device. Unfortunately, we have to use a proprietary video player, hence why I can't use the normal video API. This is sadly out of my control.
The app waits for the user to select a Display and launch a video. I would say that it works well approximately 50% of the time. Often, audio will cease to play while the video continues. Sometimes (but more rarely) the opposite happens- the Cast screen turns black while audio continues. And there is often audio and video skipping while the video plays, which isn't experienced when just viewing on the device.
I gather playing video over Remote Display isn't ideal, but I'd think audio and video should continue streaming throughout, especially since Remote Display was created for graphic-intensive games in-mind.
Also, the fact that audio stops when the activity is pushed into the background is a bit of a deal-breaker. Are there any plans to change this?
Here are some pieces of code that show how I'm creating the connection and starting video. Maybe I'm doing something dumb that causes it to perform poorly?
This code is called when the user selects a device from the MediaRouteChooserDialog:
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
selectedDevice = CastDevice.getFromBundle(info.getExtras());
Intent intent = new Intent(mainActivity,
ExampleMainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("cast", true);
PendingIntent notificationPendingIntent = PendingIntent.getActivity(mainActivity, 0, intent, 0);
CastRemoteDisplayLocalService.NotificationSettings settings =
new CastRemoteDisplayLocalService.NotificationSettings.Builder()
.setNotificationPendingIntent(notificationPendingIntent).build();
CastRemoteDisplayLocalService.startService(
mainActivity,
ExamplePresentationService.class,
config.getCastId(castButton.getContext()),
selectedDevice,
settings,
new CastRemoteDisplayLocalService.Callbacks() {
#Override
public void onRemoteDisplaySessionStarted(CastRemoteDisplayLocalService service) {
Log.d(TAG, "onServiceStarted");
}
#Override
public void onRemoteDisplaySessionError(Status errorReason) {
Log.d(TAG, "onServiceError: " + errorReason.getStatusCode());
}
}
);
}
My CastRemoteDisplayLocalService creates the CastPresentation in its createPresentation method:
#TargetApi(17)
private void createPresentation(Display display) {
dismissPresentation();
mPresentation = new PresentationPlayer(this, display, castHelper, adManager);
try {
mPresentation.show();
//mMediaPlayer.start();
} catch (WindowManager.InvalidDisplayException ex) {
Log.e(TAG, "Unable to show presentation, display was removed.", ex);
dismissPresentation();
}
}
And when the user selects a video, the following code is executed in CastPresentation:
public void startVideo(VideoData data) {
FrameLayout videoBase = (FrameLayout)findViewById(R.id.cast_video_frame);
videoBase.setVisibility(View.VISIBLE);
toggleLogoScreen(false);
if (player != null) {
player.stop();
player.close();
player = null;
videoBase.setVisibility(View.VISIBLE);
}
player = CvpPlayer.create(PlayerConstants.PlayerType.NEXSTREAM, castHelper.getExampleMainActivity(), videoBase);
player.setPlayerListener(this);
player.initPlayer();
}
Any ideas are greatly appreciated.
I have found a similar question, but I want something different.
I noticed that, when you don't have any connectivity, and you try to start Speech Recognition in an app, say through the RecognizerIntent class, you get a "no network connectivity - tap to view connectivity status" (see attached image), and if you click, a new Card with connectivity status appears.
How can I copy this behaviour in my own Activity, using the GDK?
EDIT: here is my code to call the Speech Recognition:
Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
if (speechIntent.resolveActivity(getPackageManager()) != null) {
speechIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Talk to set your title:");
speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
Log.d(TAG, "Starting to record speech title");
startActivityForResult(speechIntent, Constants.SPEECH_TITLE_REQUEST_CODE);
}
Ok, I later found an answer to my problem. I'm using the MessageDialog class provided by pif
Here is how I am calling the card:
MessageDialog localDialog = new MessageDialog.Builder(context)
.setMessage("No network connectivity")
.setSecondaryMessage("Tap to view connection settings")
.setIcon(R.drawable.ic_cloud_sad_medium)
.setIsError(true)
.setDismissable(true)
.setAutoHide(false)
.setExpanded(true)
.setShowProgress(false)
.setIsManual(false)
.setListener(new MessageDialog.SimpleListener() {
public boolean onConfirmed() {
Log.d(TAG+"_noConnDialog", "onConfirm");
return true;
}
public void onDismissed() {
Log.d(TAG+"_noConnDialog", "onDismissed");
((Activity)context).finish();
}
public void onDone() {
Log.d(TAG+"_noConnDialog", "onDone");
Intent localIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
localIntent.putExtra("settings_id", 0);
context.startActivity(localIntent);
((Activity)context).finish();
}
}).build();
localDialog.show();
Notice that, as indicated in pif's disclaimer,
This is just for educational purposes and should not be used in any production apps until Google releases something similar officially.
I hope, Google will publish a set of Google Glass Views in the future releases of GDK. We really need them! Especially that awesome progress bar!
AFAIK the Glass Developer Team has not released these functionalities in the GDK yet.
I'm pretty new with Android programming. But I have been working on this for over a week now, and it starts to get booooring.
My idea is that I want to connect two devices using Wifi Direct. But I only want to connect to those which are running my application. Besides, I want the users to be able to see some information of the other devices (such as user name), not just the MAC or the Android_XXXX name included in the WifiP2pDevice. That's why I decided that a device looking for other devices, should both start the application service and search for peers which are also broadcasting this service.
The problem (I'm testing with two real devices) is that, even though they are running exactly the same code, only one of them is getting the service discovery callbacks (the onDnsSd... listeners below). So, one side acts in the proper way, but not the other. Moreover I'm getting "old" services, meaning that apparently each time I start de service (even though I cancel previously started services), that service seems to be still broadcast during at least some minutes.
I include a shortened version of my code:
public class MoveFlufietsDialogFragment extends DialogFragment implements ChannelListener, DeviceActionListener {
public final HashMap<String, FlufietsPeer> mBuddies = new HashMap<String, FlufietsPeer>();
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mManager = (WifiP2pManager) getActivity().getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(getActivity(), getActivity().getMainLooper(), null);
...
startRegistration();
discoverFlufietsService();
...
}
public void discoverFlufietsService() {
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
// This and the next listener are only called in one of the devices.
String serviceName = (String) record.get("serviceName");
if ((serviceName != null) && (serviceName.equals("flufiets")) {
// I put the record data in the mBuddies HashMap.
...
mBuddies.put(device.deviceAddress, myPeerDataStructure);
}
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
if (mBuddies.containsKey(resourceType.deviceAddress)) {
FlufietsPeer flufietsPeer = mBuddies.get(resourceType.deviceAddress);
WiFiPeerListAdapter adapter = ((WiFiPeerListAdapter) mFragmentList.getListAdapter());
adapter.add(flufietsPeer);
adapter.notifyDataSetChanged();
}
}
};
mManager.setDnsSdResponseListeners(mChannel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(mChannel, serviceRequest, new ActionListener() {
// onSuccess/onFailure toasts.
});
mManager.discoverServices(mChannel, new WifiP2pManager.ActionListener() {
// onSuccess/onFailure toasts.
});
}
public void startRegistration() {
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
Map record = new HashMap();
record.put("serviceName", "flufiets");
...
WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(flufietsService, "_tcp", record);
mManager.addLocalService(mChannel, serviceInfo, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
#Override
public void onResume() {
super.onResume();
mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
getActivity().registerReceiver(mReceiver, mIntentFilter);
}
#Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(mReceiver);
}
#Override
public void onStop() {
super.onStop();
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
...
}
The problem doesn't seem to be related with the device itself (sometimes it works, sometimes it doesn't, but always only in one of them). I suspect it has to do with either trying to discover a service that we ourselves are broadcasting, or having the same service being offered by two devices. I have tried changing the names of the service, so each device would offer either a "send" or "receive" service, but it doesn't work. I only get the callbacks called (onDnsSd...) in one of the devices.
And that thing about getting old services, when I always clear them, is weird (I do include a timestamp in the service record data, and I could always discard all but the last, but doesn't seem to be logical).
Any ideas? ANY help would be VERY appreciated, because writing the application is not funny any more (:-)=
Thanks a lot!
You need to wait until the clearLocalService call succeeds before adding the local service later. So put the addLocalService call into the onSuccess callback of the clearLocalServices.