From 57dd737443a174379eb638450e4888500d8e4a23 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 27 Jul 2015 18:11:14 -0700 Subject: Work on issue #21516866: Implement voice interaction in ResolverActivity The main change here is to not allow the dialog to go in to its "focus on the last app the user selected" when running in voice interaction mode, instead just always giving a simple list. This also fixes some problems with cleaning up active commands when an activity finishes and not forcing the current session to go away when the screen is turned off. Also added some debug help, having activity print the state of the voice interactor. Change-Id: Ifebee9c74d78398a730a280bb4970f47789dadf5 --- core/java/android/app/Activity.java | 8 +- core/java/android/app/VoiceInteractor.java | 166 ++++++++++++++++++++- .../service/voice/VoiceInteractionSession.java | 117 +++++++++++++++ .../voice/VoiceInteractionSessionService.java | 13 ++ .../com/android/internal/app/ResolverActivity.java | 9 +- 5 files changed, 309 insertions(+), 4 deletions(-) (limited to 'core/java') diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index e49acfa..bdea608 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1864,7 +1864,10 @@ public class Activity extends ContextThemeWrapper nci.children = children; nci.fragments = fragments; nci.loaders = loaders; - nci.voiceInteractor = mVoiceInteractor; + if (mVoiceInteractor != null) { + mVoiceInteractor.retainInstance(); + nci.voiceInteractor = mVoiceInteractor; + } return nci; } @@ -5547,6 +5550,9 @@ public class Activity extends ContextThemeWrapper mFragments.dumpLoaders(innerPrefix, fd, writer, args); mFragments.getFragmentManager().dump(innerPrefix, fd, writer, args); + if (mVoiceInteractor != null) { + mVoiceInteractor.dump(innerPrefix, fd, writer, args); + } if (getWindow() != null && getWindow().peekDecorView() != null && diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java index bf7458c..823c427 100644 --- a/core/java/android/app/VoiceInteractor.java +++ b/core/java/android/app/VoiceInteractor.java @@ -27,6 +27,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.util.ArrayMap; +import android.util.DebugUtils; import android.util.Log; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.IVoiceInteractorCallback; @@ -34,6 +35,8 @@ import com.android.internal.app.IVoiceInteractorRequest; import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; /** @@ -68,6 +71,7 @@ public final class VoiceInteractor { Context mContext; Activity mActivity; + boolean mRetaining; final HandlerCaller mHandlerCaller; final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() { @@ -272,6 +276,29 @@ public final class VoiceInteractor { public void onDetached() { } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + DebugUtils.buildShortClassTag(this, sb); + sb.append(" "); + sb.append(getRequestTypeName()); + sb.append(" name="); + sb.append(mName); + sb.append('}'); + return sb.toString(); + } + + void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + writer.print(prefix); writer.print("mRequestInterface="); + writer.println(mRequestInterface.asBinder()); + writer.print(prefix); writer.print("mActivity="); writer.println(mActivity); + writer.print(prefix); writer.print("mName="); writer.println(mName); + } + + String getRequestTypeName() { + return "Request"; + } + void clear() { mRequestInterface = null; mContext = null; @@ -333,6 +360,18 @@ public final class VoiceInteractor { public void onConfirmationResult(boolean confirmed, Bundle result) { } + void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + super.dump(prefix, fd, writer, args); + writer.print(prefix); writer.print("mPrompt="); writer.println(mPrompt); + if (mExtras != null) { + writer.print(prefix); writer.print("mExtras="); writer.println(mExtras); + } + } + + String getRequestTypeName() { + return "Confirmation"; + } + IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException { return interactor.startConfirmation(packageName, callback, mPrompt, mExtras); @@ -515,6 +554,38 @@ public final class VoiceInteractor { public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) { } + void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + super.dump(prefix, fd, writer, args); + writer.print(prefix); writer.print("mPrompt="); writer.println(mPrompt); + if (mOptions != null) { + writer.print(prefix); writer.println("Options:"); + for (int i=0; i list = new ArrayList(N); + ArrayList list = new ArrayList<>(N); for (int i=0; i reqs = makeRequestList(); if (reqs != null) { @@ -807,6 +943,16 @@ public final class VoiceInteractor { req.mContext = null; } } + if (!mRetaining) { + reqs = makeRequestList(); + if (reqs != null) { + for (int i=0; i 0) { + writer.print(prefix); writer.println("Active voice requests:"); + for (int i=0; i payloadIntents, Intent[] initialIntents, List rList, boolean alwaysUseOption) { + // The last argument of createAdapter is whether to do special handling + // of the last used choice to highlight it in the list. We need to always + // turn this off when running under voice interaction, since it results in + // a more complicated UI that the current voice interaction flow is not able + // to handle. mAdapter = createAdapter(this, payloadIntents, initialIntents, rList, - mLaunchedFromUid, alwaysUseOption); + mLaunchedFromUid, alwaysUseOption && !isVoiceInteraction()); final int layoutId; if (mAdapter.hasFilteredItem()) { -- cgit v1.1