Way to nest multiple voice triggers when launching an app with GDK - google-glass

Is there a way to nest voice triggers when launching an app on Google Glass using the GDK? For example instead of just saying "ok, glass" -> "What's its power level?" I'd like to have the app present an option. For example "ok, glass" -> "What's its power level?" -> "Over 9000" OR "Under 9000". Any help would be great!

If you have multiple activities/services installed on Glass that have the same voice trigger intent filter, all of their names (based on the android:label attribute of the <activity> or <service> tag in AndroidManifest.xml) will appear in a disambiguation "submenu" when you speak that voice trigger.
For example (assume that res/xml/play_a_game_trigger.xml represents a voice trigger for the string "play a game"):
<activity android:label="Tennis">
<intent-filter>
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/play_a_game_trigger" />
</activity>
<activity android:label="Bowling">
<intent-filter>
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/play_a_game_trigger" />
</activity>
would give you a voice menu flow that looks like
ok glass → play a game → Tennis
Bowling
Do note, however, that this menu would also include activities/services from other APKs that use the same voice trigger as well.
You can find more details at the Voice Input page of the GDK documentation.

The proper way to do this is using an input tag inside the trigger
<trigger keyword="#string/start_app" >
<input prompt="#string/promt_text" />
</trigger>
This prompts an input and waits for more audio speech.
Then in your activity you can capture this text with:
ArrayList<String> text = getIntent().getExtras().getStringArrayList(RecognizerIntent.EXTRA_RESULTS);

Related

how can I deeplink an app from Google Assistant?

I'm creating a dialogflow agent integrated with Google Assistant.
What I'd like to do is to open an app (my app) when a proper intent is matched. I've seen that actions like Youtube, Spotify etc. are able to do that, for example I can tell the Youtube action "search for cats video" and the Youtube app will open with a list of cats videos.
I tried to use the DeepLink class but I then noticed it's deprecated.
DeepLink class
Is there any way you can suggest me to do this?
Thanks in advance
I think you are looking for App Actions. Here are the steps you need to follow:
Find the right built-in intent. actions.intent.OPEN_APP_FEATURE should be the right one for you.
Create and update actions.xml. It should look like
<?xml version="1.0" encoding="UTF-8"?>
<!-- This is a sample actions.xml -->
<actions>
<action intentName="actions.intent.OPEN_APP_FEATURE">
<!-- Use url from inventory match for deep link fulfillment -->
<fulfillment urlTemplate="{#url}" />
<!-- Define parameters with inventories here -->
<parameter name="feature">
<entity-set-reference entitySetId="featureParamEntitySet" />
</parameter>
</action>
<entity-set entitySetId="featureParamEntitySet">
<!-- Provide a URL per entity -->
<entity url="myapp://deeplink/one" name="featureParam_one" alternateName="#array/featureParam_one_synonyms" />
<entity url="myapp://deeplink/two" name="featureParam_two" alternateName="#array/featureParam_two_synonyms" />
</entity-set>
</actions>

Glass XE17.1 - tap on "ok glass" menu with custom voice command is broken

I used to create one voice trigger that prompts user to speak additional commands before starting my Activity or Service, like:
ok glass
+-David
++-find me a parking lot
++-show me stock chart
in XE17 or early version(XE16.2), either using voice command or tap on "ok glass" menu will shows a list(vertical list with voice) or a list of command cards (horizontal menu), but in XE17.1 update, when I tap on 'ok glass', it just hangs and no menu cards shows up, only ok glass launcher, no other default voice triggers cards, after a short debug, I found it's the same voice trigger
"android:resource="#xml/voice_trigger"
declare in AndroidMenifest.xml caused the issue, but voice command still works, could someone help? Thanks!
ps. and also, Im trying input prompt with two more prompt won't work.
<input prompt="#string/glass_voice_prompt"/>
MY CODE (GDK API19, rev.5)
<> AndroidManifest.xml
<uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT"/>
<activity
android:name=".PromptActivity"
android:label="#string/app_name"
android:theme="#style/MenuTheme"
android:icon="#drawable/ic"
android:enabled="true" />
<activity-alias
android:name="find me a parking lot"
android:label="find me a parking lot"
android:targetActivity=".PromptActivity"
android:icon="#drawable/hippo_icon" >
<intent-filter>
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data
android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/hippo_voice_trigger_david" /> <!---HERE IS THE PROBLEM(two same voice trigger won't allow any more->
</activity-alias>
<activity-alias
android:name="show me stock chart"
android:label="show me stock chart"
android:targetActivity=".PromptActivity"
android:icon="#drawable/hippo_icon" >
<intent-filter>
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data
android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/hippo_voice_trigger_david" /> <!---HERE IS THE PROBLEM->
</activity-alias>
<> hippo_voice_trigger_david.xml
<?xml version="1.0" encoding="utf-8"?>
<trigger keyword="#string/glass_voice_david_prompt">
<constraints network="true" camera="true" />
</trigger>
<> res/values/strings.xml
<string name="glass_voice_david_prompt">David</string>
<> Here is the LogCat Exception:
FATAL EXCEPTION: main
Process: com.google.glass.home, PID: 5738
java.lang.NullPointerException
at com.google.glass.home.voice.TouchMainMenuActivity.onCreateOptionsMenu(TouchMainMenuActivity.java:122)
at android.app.Activity.onCreatePanelMenu(Activity.java:2543)
at com.android.internal.policy.impl.PhoneWindow.preparePanel(PhoneWindow.java:439)
at com.android.internal.policy.impl.PhoneWindow.openPanel(PhoneWindow.java:602)
at com.android.internal.policy.impl.PhoneWindow.openPanel(PhoneWindow.java:555)
at android.app.Activity.openOptionsMenu(Activity.java:2878)
at com.google.glass.app.GlassVoiceActivity.openOptionsMenu(GlassVoiceActivity.java:456)
at com.google.glass.home.voice.TouchMainMenuActivity.onAttachedToWindow(TouchMainMenuActivity.java:93)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onAttachedToWindow(PhoneWindow.java:2793)
at android.view.View.dispatchAttachedToWindow(View.java:12592)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2458)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1242)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1025)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5699)

Opening GDK Glassware through Mirror API Glassware MenuItem

I have problem integrating GDK Glassware and Mirror API Glassware as described here. I need to open GDK glassware application using Mirroe api Glassware app MenuItem. Can I send data bundle with intent. Does anybody have an idea about that.
Thank you.
I have finally figured out a way to do that
First add your custom scheme to android activity tag in AndroidManifest.xml
<activity
android:name="com.sanath.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="com.sanath.scheme" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.google.android.glass.VoiceTrigger"
android:resource="#xml/vision_voice_trigger" />
</activity>
Then in Glassware timeline MenuItem add like following
new MenuItem(){
Action = "OPEN_URI",
Payload = "com.sanath.scheme://open/Welcome/2014",
Values = new MenuValue[]
{
new MenuValue()
{
DisplayName = "Open",
State = "DEFAULT"
},
new MenuValue()
{
DisplayName = "Launching",
State = "PENDING"
},
new MenuValue()
{
DisplayName = "Launched",
State = "CONFIRMED"
},
},
},
}
Then inside your Activity OnCreate method you can get data as following
Uri data = getIntent().getData();
List params = data.getPathSegments();
String param0 = params.get(0); // "welcome"
String param1 = params.get(1); //"2014"
String welcomeMsg = param0+" to "+param1;
/*show time line card
* */
Card welcomeCard =new Card(this);
welcomeCard.setText(welcomeMsg);
welcomeCard.setFootnote(param1);
View view =welcomeCard.toView();
setContentView(view);
Hope this will help others
It is not possible to provide data through bundle, but you can use query parameters or hash fragment in your URI to provide the necessary data.
Example:
myscheme://<SOME_PATH>?param1=value1&param2&value2
Then, in your GDK Glassware, simply parse the query parameters and process their values.

Gradle: How to merge Android manifest files for different buildTypes which need the same Activity, but with different intent-filters

so I'm trying to use gradle to create a separate buildType, but that buildType needs to use different characteristics for the same Activity. In this case, my splash activity needs a different intent-filter depending on buildType. Is this possible?
I get the following error in gradle:
:Tinder:processUtestManifest
[AndroidManifest.xml:67, AndroidManifest.xml:38] Trying to merge incompatible /manifest/application/activity[#name=com.<company_name>.activities.ActivitySplash] element:
<activity
#android:name="com.<company_name>.activities.ActivitySplash"
<intent-filter>
<action
-- #android:name="android.intent.action.MAIN">
<activity
#android:name="com.<company_name>.activities.ActivitySplash"
<intent-filter>
<action
++ #android:name="com.apphance.android.LAUNCH">
It's not possible to merge the intent-filter separately at the moment so I would recommend copying the whole <activity> node into
src/buildtype1/AndroidManifest.xml
and
src/buildtype2/AndroidManifest.xml
and it'll get merged automatically into the final manifest (of course you also want to remove it from the main manifest).
Let me post a full solution that works. In this case, the application manages intent filters for both images and videos. However, for a particular flavor, we only want to capture videos, not images.
Say your activity is defined like this:
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="#string/app_name"
android:launchMode="singleTop"
android:screenOrientation="landscape"
android:theme="#style/CameraTheme">
<intent-filter>
<action android:name="android.media.action.IMAGE_CAPTURE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.media.action.VIDEO_CAPTURE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
For your flavor named myFlavor, that I assume you already have, you have to have this in your AndroidManifest.xml file:
<!-- Remove the intent filter for images. MyFlavor is only for videos. -->
<activity
android:name="com.androidsx.heliumvideochanger.MainActivity"
tools:node="merge">
<intent-filter tools:node="remove">
<action android:name="android.media.action.IMAGE_CAPTURE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
Sync with Gradle, and check the final manifest, that is usually in myApp/build/intermediates/manifests/full/myFlavor/debug/AndroidManifest.xml
Change the AndroidManifest in the consuming app/lib from:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<activity android:name="com.<company_name>.activities.ActivitySplash">
To:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
...
<activity android:name="com.<company_name>.activities.ActivitySplash"
tools:merge="override">

keeping data during orientation changes by using fragments

I am trying to understand fragments. All the examples I read is about having a main activity and then two sub fragments.
The issue is that my program has only 1 activity. Can I make it a fragment?
Current ui main class
public class MainActivity extends Activity {}
Can I make it
public class MainActivity extends Fragment {}
The program I am trying to create will constantly monitor phone variables and display logs in a textView. I don't want to lose the logs when the user changes the orientation or some other change when the os destroys the ui.
The UI is basically 1 textView that gets filled by a runnable that updates the textView every 5 seconds with the content of a linked list. I don't want to lose the content of the linked list basically.
I checked getLastNonConfigurationInstance() but it seems it's depreciated so I don't want to use that
Any help would be highly appreciated.
Amish
Found answer here:
http://blog.webagesolutions.com/archives/458
So after a lot of searching I found that if you add the following:
android:configChanges="orientation|screenSize"
in the androidManifest.xml, the os will not destroy the activity when switching from portrait mode to landscape mode.
My xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.axr0284.phonecontrol"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="15" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.axr0284.phonecontrol.MainActivity"
android:label="#string/app_name"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Hope this helps somebody,
Amish