330 lines
14 KiB
Plaintext
330 lines
14 KiB
Plaintext
page.title=Optimizing Content for the Assistant
|
||
page.metaDescription=Support contextually relevant actions through the Assist API.
|
||
page.tags=assist, accessibility, now, now on tap
|
||
meta.tags="assistant", "marshmallow", "now"
|
||
page.image=images/cards/card-assist_16-9_2x.png
|
||
|
||
page.article=true
|
||
@jd:body
|
||
|
||
<div id="tb-wrapper">
|
||
<div id="tb">
|
||
<h2>In this document</h2>
|
||
<ol>
|
||
<li><a href="#assist_api">Using the Assistant</a>
|
||
<ol>
|
||
<li><a href="#source_app">Source app</a></li>
|
||
<li><a href="#destination_app">Destination app</a></li>
|
||
</ol>
|
||
</li>
|
||
<li><a href="#implementing_your_own_assistant">Implementing Your
|
||
Own Assistant</a></li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
|
||
<p>
|
||
Android 6.0 Marshmallow introduces a new way for users to engage with apps
|
||
through the assistant. The assistant is a top-level window that users can view to obtain
|
||
contextually relevant actions for the current activity. These actions might include deep links
|
||
to other apps on the device.</p>
|
||
|
||
<p>
|
||
Users activate the assistant with a long press on the Home button or by saying a
|
||
<a href="{@docRoot}reference/android/service/voice/AlwaysOnHotwordDetector.html">keyphrase</a>.
|
||
In response, the system opens a top-level window that displays contextually
|
||
relevant actions.
|
||
</p>
|
||
|
||
<p>
|
||
Google App implements the assistant overlay window through a feature called
|
||
Now on Tap, which works with the Android platform-level functionality. The system allows
|
||
the user to select an assistant app, which obtains contextual information from your app
|
||
using Android’s Assist API.
|
||
</p>
|
||
<p>
|
||
This guide explains how Android apps use Android's Assist API to improve the assistant
|
||
user experience.
|
||
<p/>
|
||
</p>
|
||
|
||
|
||
<h2 id="assist_api">Using the Assistant</h2>
|
||
|
||
<p>
|
||
Figure 1 illustrates a typical user interaction with the assistant. When the user long-presses
|
||
the Home button, the Assist API callbacks are invoked
|
||
in the <em>source</em> app (step 1). The assistant renders the overlay window (steps 2 and 3),
|
||
and then the user selects the action to perform. The assistant executes the selected action,
|
||
such as firing an intent with a deep link to the (<em>destination</em>) restaurant app (step 4).
|
||
</p>
|
||
|
||
<div>
|
||
<img src="{@docRoot}images/training/assistant/image01.png">
|
||
<p class="img-caption" style="text-align:center;">
|
||
Figure 1. Assistant interaction example with the Now on Tap feature of
|
||
the Google App
|
||
</p>
|
||
</div>
|
||
|
||
<p>
|
||
Users can configure the assistant by selecting <strong>Settings > Apps > Default Apps >
|
||
Assist & voice input</strong>. Users can change system options such as accessing
|
||
the screen contents as text and accessing a screenshot, as shown in Figure 2.
|
||
</p>
|
||
|
||
<div id="assist-input-settings" style="float:right;margin:1em;max-width:300px">
|
||
<img src="{@docRoot}images/training/assistant/image02.png">
|
||
<p class="img-caption" style="text-align:center;">
|
||
Figure 2. Assist & voice input settings
|
||
</p>
|
||
</div>
|
||
|
||
<h3 id="source_app">Source app</h3>
|
||
|
||
<p>
|
||
To ensure that your app works with the assistant as a source of information for the user,
|
||
you need only follow <a href=
|
||
"{@docRoot}guide/topics/ui/accessibility/apps.html">accessibility best
|
||
practices</a>. This section describes how to provide additional information
|
||
to help improve the assistant user experience as well as scenarios
|
||
that need special handling, such as custom Views.
|
||
</p>
|
||
<h4 id="share_additional_information_with_the_assistant">Share additional information
|
||
with the assistant</h4>
|
||
|
||
<p>
|
||
In addition to the text and the screenshot, your app can share
|
||
other information with the assistant. For example, your music
|
||
app can choose to pass current album information so that the assistant can
|
||
suggest smarter actions tailored to the current activity.
|
||
</p>
|
||
|
||
<p>
|
||
To provide additional information to the assistant, your app provides
|
||
<em>global application context</em> by registering an app listener and
|
||
supplies activity-specific information with activity callbacks as shown in
|
||
Figure 3:
|
||
</p>
|
||
|
||
<div>
|
||
<img src="{@docRoot}images/training/assistant/image03.png">
|
||
<p class="img-caption" style="text-align:center;">
|
||
Figure 3. Assist API lifecycle sequence diagram
|
||
</p>
|
||
</div>
|
||
|
||
<p>
|
||
To provide global application context, the app creates an implementation of
|
||
{@link android.app.Application.OnProvideAssistDataListener} and registers it
|
||
using {@link
|
||
android.app.Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener) registerOnProvideAssistDataListener()}.
|
||
To provide activity-specific contextual information, the activity
|
||
overrides {@link android.app.Activity#onProvideAssistData(android.os.Bundle) onProvideAssistData()}
|
||
and {@link
|
||
android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent) onProvideAssistContent()}.
|
||
The two activity methods are called <em>after</em> the optional global
|
||
callback is invoked. Because the callbacks execute on the main thread, they should
|
||
complete <a href="{@docRoot}training/articles/perf-anr.html">promptly</a>.
|
||
The callbacks are invoked only when the activity is <a href=
|
||
"{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">running</a>.
|
||
</p>
|
||
|
||
<h5 id="providing_context">Providing context</h5>
|
||
|
||
<p>
|
||
When the user activates the assistant,
|
||
{@link android.app.Activity#onProvideAssistData(android.os.Bundle) onProvideAssistData()} is called to build a full
|
||
{@link
|
||
android.content.Intent#ACTION_ASSIST} Intent with all of the context of the
|
||
current application represented as an instance of the {@link
|
||
android.app.assist.AssistStructure}. You can override this method to place
|
||
anything you like into the bundle to appear in the
|
||
{@link android.content.Intent#EXTRA_ASSIST_CONTEXT} part of the assist intent.
|
||
</p>
|
||
|
||
<h5 id="describing_content">Describing content</h5>
|
||
|
||
<p>
|
||
Your app can implement {@link
|
||
android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent) onProvideAssistContent()}
|
||
to improve the assistant user experience by providing content-related references
|
||
related to the current activity. You can describe the app content using the
|
||
common vocabulary defined by <a href="https://schema.org" class="external-link">Schema.org</a>
|
||
through a JSON-LD object. In the example below, a music app provides
|
||
structured data to describe the music album that the user is currently
|
||
viewing:
|
||
</p>
|
||
|
||
<pre class="prettyprint">
|
||
@Override
|
||
public void onProvideAssistContent(AssistContent <strong>assistContent</strong>) {
|
||
super.onProvideAssistContent(<strong>assistContent</strong>);
|
||
|
||
String structuredJson = <strong>new </strong>JSONObject()
|
||
.put(<strong>"@type"</strong>, <strong>"MusicRecording"</strong>)
|
||
.put(<strong>"@id"</strong>, <strong>"https://example.com/music/recording"</strong>)
|
||
.put(<strong>"name"</strong>, <strong>"Album Title"</strong>)
|
||
.toString();
|
||
|
||
<strong>assistContent</strong>.setStructuredData(structuredJson);
|
||
}
|
||
</pre>
|
||
|
||
<p>
|
||
You can also improve the user experience with custom implementations of
|
||
{@link
|
||
android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent) onProvideAssistContent()},
|
||
which can provide the following benefits:
|
||
</p>
|
||
<ul>
|
||
<li><a href="{@docRoot}reference/android/app/assist/AssistContent.html#setIntent(android.content.Intent)">
|
||
Adjusts the provided content
|
||
intent</a> to
|
||
better reflect the top-level context of the activity.</li>
|
||
<li><a href="{@docRoot}reference/android/app/assist/AssistContent.html#setWebUri(android.net.Uri)">
|
||
Supplies the URI</a>
|
||
of the displayed content.</li>
|
||
<li>Fills in {@link
|
||
android.app.assist.AssistContent#setClipData(android.content.ClipData) setClipData()} with additional
|
||
content of interest that the user is currently viewing.</li>
|
||
</ul>
|
||
<p class="note">
|
||
<strong>Note: </strong>Apps that use a custom text selection implementation likely need
|
||
to implement {@link
|
||
android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent) onProvideAssistContent()}
|
||
and call {@link android.app.assist.AssistContent#setClipData(android.content.ClipData) setClipData()}.
|
||
</p>
|
||
|
||
<h4 id="default_implementation">Default implementation</h4>
|
||
|
||
<p>
|
||
If neither the {@link
|
||
android.app.Activity#onProvideAssistData(android.os.Bundle) onProvideAssistData()} nor the {@link
|
||
android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent) onProvideAssistContent()}
|
||
callback is implemented, the system still proceeds and passes the
|
||
automatically collected information to the assistant unless the current
|
||
window is flagged as <a href="#excluding_views">secure</a>.
|
||
As shown in Figure 3, the system uses the default implementations of {@link
|
||
android.view.View#onProvideStructure(android.view.ViewStructure) onProvideStructure()} and {@link
|
||
android.view.View#onProvideVirtualStructure(android.view.ViewStructure) onProvideVirtualStructure()} to
|
||
collect text and view hierarchy information. If your view implements custom
|
||
text drawing, override {@link
|
||
android.view.View#onProvideStructure(android.view.ViewStructure) onProvideStructure()} to provide
|
||
the assistant with the text shown to the user by calling {@link
|
||
android.view.ViewStructure#setText(java.lang.CharSequence) setText(CharSequence)}.
|
||
</p>
|
||
|
||
<p>
|
||
<em>In most cases, implementing accessibility support enables the
|
||
assistant to obtain the information it needs.</em> To implement accessibility support,
|
||
observe the best practices described in <a href=
|
||
"{@docRoot}guide/topics/ui/accessibility/apps.html">Making Applications
|
||
Accessible</a>, including the following:</p>
|
||
|
||
<ul>
|
||
<li>Provide {@link android.R.attr#contentDescription
|
||
android:contentDescription} attributes.</li>
|
||
<li>Populate {@link
|
||
android.view.accessibility.AccessibilityNodeInfo} for custom views.</li>
|
||
<li>Make
|
||
sure that custom {@link android.view.ViewGroup ViewGroup} objects correctly
|
||
<a href="{@docRoot}reference/android/view/ViewGroup.html#getChildAt(int)">expose</a>
|
||
their children.</li>
|
||
</ul>
|
||
|
||
<h4 id="excluding_views">Excluding views from the assistant</h4>
|
||
|
||
<p>
|
||
To handle sensitive information, your app can exclude the current view from the assistant
|
||
by setting the {@link android.view.WindowManager.LayoutParams#FLAG_SECURE
|
||
FLAG_SECURE} layout parameter of the {@link android.view.WindowManager}. You must set {@link
|
||
android.view.WindowManager.LayoutParams#FLAG_SECURE
|
||
FLAG_SECURE} explicitly for
|
||
every window created by the activity, including dialogs. Your app can also use
|
||
{@link android.view.SurfaceView#setSecure(boolean) setSecure()} to exclude
|
||
a surface from the assistant. There is no
|
||
global (app-level) mechanism to exclude all views from the assistant. Note
|
||
that {@link android.view.WindowManager.LayoutParams#FLAG_SECURE
|
||
FLAG_SECURE} does not cause the Assist API callbacks to stop
|
||
firing. The activity that uses {@link android.view.WindowManager.LayoutParams#FLAG_SECURE
|
||
FLAG_SECURE} can still explicitly
|
||
provide information to the assistant using the callbacks described earlier
|
||
this guide.
|
||
</p>
|
||
|
||
<p class="note"><strong>Note: </strong>For enterprise accounts (Android for Work),
|
||
the administrator can disable
|
||
the collection of assistant data for the work profile by using the {@link
|
||
android.app.admin.DevicePolicyManager#setScreenCaptureDisabled(android.content.ComponentName, boolean)
|
||
setScreenCaptureDisabled()} method of the {@link android.app.admin.DevicePolicyManager} API.</p>
|
||
|
||
<h4 id="voice_interactions">Voice interactions</h4>
|
||
|
||
<p>
|
||
Assist API callbacks are also invoked upon
|
||
<a href="{@docRoot}reference/android/service/voice/AlwaysOnHotwordDetector.html">keyphrase
|
||
detection</a>. For more information, see the
|
||
<a href="https://developers.google.com/voice-actions/" class="external-link">Voice
|
||
Actions</a> documentation.
|
||
</p>
|
||
|
||
<h4 id="z-order_considerations">Z-order considerations</h4>
|
||
|
||
<p>
|
||
The assistant uses a lightweight overlay window displayed on top of the
|
||
current activity. Because the user can activate the assistant at any time,
|
||
don't create permanent <a
|
||
href="{@docRoot}reference/android/Manifest.permission.html#SYSTEM_ALERT_WINDOW">
|
||
system alert</a> windows that interfere with the overlay window, as shown in
|
||
Figure 4.
|
||
</p>
|
||
|
||
<div style="">
|
||
<img src="{@docRoot}images/training/assistant/image04.png">
|
||
<p class="img-caption" style="text-align:center;">
|
||
Figure 4. Assist layer Z-order
|
||
</p>
|
||
</div>
|
||
|
||
<p>
|
||
If your app uses <a
|
||
href="{@docRoot}reference/android/Manifest.permission.html#SYSTEM_ALERT_WINDOW">
|
||
system alert</a> windows, remove them promptly because leaving them on the
|
||
screen degrades the user experience.
|
||
</p>
|
||
|
||
<h3 id="destination_app">Destination app</h3>
|
||
|
||
<p>
|
||
The assistant typically takes advantage of deep linking to find destination apps. To make your
|
||
app a potential destination app, consider adding <a href=
|
||
"{@docRoot}training/app-indexing/deep-linking.html">deep linking</a> support. The matching
|
||
between the current user context and deep links or other potential actions displayed in the
|
||
overlay window (shown in step 3 in Figure 1) is specific to the assistant’s implementation.
|
||
For
|
||
example, the Google App uses deep linking and <a href=
|
||
"https://developers.google.com/app-indexing/" class="external-link">Firebase App Indexing</a> in order to
|
||
drive traffic to destination apps.
|
||
</p>
|
||
|
||
<h2 id="implementing_your_own_assistant">Implementing Your Own Assistant </h2>
|
||
|
||
<p>
|
||
You may wish to implement your own assistant. As shown in <a href="#assist-input-settings">Figure
|
||
2</a>, the user can select the active assistant app. The
|
||
assistant app must provide an implementation of {@link
|
||
android.service.voice.VoiceInteractionSessionService} and {@link
|
||
android.service.voice.VoiceInteractionSession} as shown in <a href=
|
||
"https://android.googlesource.com/platform/frameworks/base/+/marshmallow-release/tests/VoiceInteraction/" class="external-link">
|
||
this <code>VoiceInteraction</code> example</a>. It also requires the {@link
|
||
android.Manifest.permission#BIND_VOICE_INTERACTION} permission. The assistant can then
|
||
receive the text and view hierarchy represented as an instance of the {@link
|
||
android.app.assist.AssistStructure} in {@link
|
||
android.service.voice.VoiceInteractionSession#onHandleAssist(android.os.Bundle,
|
||
android.app.assist.AssistStructure,android.app.assist.AssistContent) onHandleAssist()}.
|
||
It receives the screenshot through {@link
|
||
android.service.voice.VoiceInteractionSession#onHandleScreenshot(android.graphics.Bitmap)
|
||
onHandleScreenshot()}.
|
||
</p>
|