diff options
9 files changed, 222 insertions, 104 deletions
diff --git a/api/current.txt b/api/current.txt index 13ebbb0daf25..1700603aaca5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3763,7 +3763,7 @@ package android.app { method public void onDetachedFromWindow(); method public void onEnterAnimationComplete(); method public boolean onGenericMotionEvent(android.view.MotionEvent); - method @NonNull public java.util.List<android.app.DirectAction> onGetDirectActions(); + method public void onGetDirectActions(@NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>); method public boolean onKeyDown(int, android.view.KeyEvent); method public boolean onKeyLongPress(int, android.view.KeyEvent); method public boolean onKeyMultiple(int, int, android.view.KeyEvent); @@ -3783,7 +3783,7 @@ package android.app { method public void onOptionsMenuClosed(android.view.Menu); method public void onPanelClosed(int, @NonNull android.view.Menu); method @CallSuper protected void onPause(); - method public void onPerformDirectAction(@NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>); + method public void onPerformDirectAction(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>); method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration); method @Deprecated public void onPictureInPictureModeChanged(boolean); method @CallSuper protected void onPostCreate(@Nullable android.os.Bundle); @@ -41836,7 +41836,7 @@ package android.service.voice { method public void onTaskStarted(android.content.Intent, int); method public void onTrimMemory(int); method public final void performDirectAction(@NonNull android.app.DirectAction, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.os.Bundle>); - method public final void requestDirectActions(@NonNull android.service.voice.VoiceInteractionSession.ActivityId, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>); + method public final void requestDirectActions(@NonNull android.service.voice.VoiceInteractionSession.ActivityId, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>); method public void setContentView(android.view.View); method public void setDisabledShowContext(int); method public void setKeepAwake(boolean); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 9ae0aa0e2978..43531eddf638 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2340,12 +2340,20 @@ public class Activity extends ContextThemeWrapper * <p>This method will be called only after {@link #onStart()} is being called and * before {@link #onStop()} is being called. * - * @return The currently supported direct actions which cannot be <code>null</code> - * or contain <code>null</null> elements. + * <p>You should pass to the callback the currently supported direct actions which + * cannot be <code>null</code> or contain <code>null</null> elements. + * + * <p>You should return the action list as soon as possible to ensure the consumer, + * for example the assistant, is as responsive as possible which would improve user + * experience of your app. + * + * @param cancellationSignal A signal to cancel the operation in progress. + * @param callback The callback to send the action list. The actions list cannot + * contain <code>null</code> elements. */ - @NonNull - public List<DirectAction> onGetDirectActions() { - return Collections.emptyList(); + public void onGetDirectActions(@NonNull CancellationSignal cancellationSignal, + @NonNull Consumer<List<DirectAction>> callback) { + callback.accept(Collections.emptyList()); } /** @@ -2354,14 +2362,13 @@ public class Activity extends ContextThemeWrapper * * @param actionId The ID for the action * @param arguments Any additional arguments provided by the caller - * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} - * if none. + * @param cancellationSignal A signal to cancel the operation in progress. * @param resultListener The callback to provide the result back to the caller * - * @see #onGetDirectActions() + * @see #onGetDirectActions(CancellationSignal, Consumer) */ public void onPerformDirectAction(@NonNull String actionId, - @Nullable Bundle arguments, @Nullable CancellationSignal cancellationSignal, + @NonNull Bundle arguments, @NonNull CancellationSignal cancellationSignal, @NonNull Consumer<Bundle> resultListener) { } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 134ab1043904..4b37461866d0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -392,6 +392,10 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final ResourcesManager mResourcesManager; + // Registry of remote cancellation transports pending a reply with reply handles. + @GuardedBy("this") + private @Nullable Map<SafeCancellationTransport, CancellationSignal> mRemoteCancellations; + private static final class ProviderKey { final String authority; final int userId; @@ -1657,32 +1661,85 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public void requestDirectActions(@NonNull IBinder activityToken, - @NonNull IVoiceInteractor interactor, @NonNull RemoteCallback callback) { + @NonNull IVoiceInteractor interactor, @Nullable RemoteCallback cancellationCallback, + @NonNull RemoteCallback callback) { + final CancellationSignal cancellationSignal = new CancellationSignal(); + if (cancellationCallback != null) { + final ICancellationSignal transport = createSafeCancellationTransport( + cancellationSignal); + final Bundle cancellationResult = new Bundle(); + cancellationResult.putBinder(VoiceInteractor.KEY_CANCELLATION_SIGNAL, + transport.asBinder()); + cancellationCallback.sendResult(cancellationResult); + } mH.sendMessage(PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions, - ActivityThread.this, activityToken, interactor, callback)); + ActivityThread.this, activityToken, interactor, cancellationSignal, callback)); } @Override - public void performDirectAction(IBinder activityToken, String actionId, Bundle arguments, - RemoteCallback cancellationCallback, RemoteCallback resultCallback) { - final CancellationSignal cancellationSignal; + public void performDirectAction(@NonNull IBinder activityToken, @NonNull String actionId, + @Nullable Bundle arguments, @Nullable RemoteCallback cancellationCallback, + @NonNull RemoteCallback resultCallback) { + final CancellationSignal cancellationSignal = new CancellationSignal(); if (cancellationCallback != null) { - final ICancellationSignal transport = CancellationSignal.createTransport(); - cancellationSignal = CancellationSignal.fromTransport(transport); + final ICancellationSignal transport = createSafeCancellationTransport( + cancellationSignal); final Bundle cancellationResult = new Bundle(); cancellationResult.putBinder(VoiceInteractor.KEY_CANCELLATION_SIGNAL, transport.asBinder()); cancellationCallback.sendResult(cancellationResult); - } else { - cancellationSignal = new CancellationSignal(); } - mH.sendMessage(PooledLambda.obtainMessage(ActivityThread::handlePerformDirectAction, ActivityThread.this, activityToken, actionId, arguments, cancellationSignal, resultCallback)); } } + private @NonNull SafeCancellationTransport createSafeCancellationTransport( + @NonNull CancellationSignal cancellationSignal) { + synchronized (ActivityThread.this) { + if (mRemoteCancellations == null) { + mRemoteCancellations = new ArrayMap<>(); + } + final SafeCancellationTransport transport = new SafeCancellationTransport( + this, cancellationSignal); + mRemoteCancellations.put(transport, cancellationSignal); + return transport; + } + } + + private @NonNull CancellationSignal removeSafeCancellationTransport( + @NonNull SafeCancellationTransport transport) { + synchronized (ActivityThread.this) { + final CancellationSignal cancellation = mRemoteCancellations.remove(transport); + if (mRemoteCancellations.isEmpty()) { + mRemoteCancellations = null; + } + return cancellation; + } + } + + private static final class SafeCancellationTransport extends ICancellationSignal.Stub { + private final @NonNull WeakReference<ActivityThread> mWeakActivityThread; + + SafeCancellationTransport(@NonNull ActivityThread activityThread, + @NonNull CancellationSignal cancellation) { + mWeakActivityThread = new WeakReference<>(activityThread); + } + + @Override + public void cancel() { + final ActivityThread activityThread = mWeakActivityThread.get(); + if (activityThread != null) { + final CancellationSignal cancellation = activityThread + .removeSafeCancellationTransport(this); + if (cancellation != null) { + cancellation.cancel(); + } + } + } + } + class H extends Handler { public static final int BIND_APPLICATION = 110; @UnsupportedAppUsage @@ -3491,27 +3548,31 @@ public final class ActivityThread extends ClientTransactionHandler { /** Fetches the user actions for the corresponding activity */ private void handleRequestDirectActions(@NonNull IBinder activityToken, - @NonNull IVoiceInteractor interactor, @NonNull RemoteCallback callback) { + @NonNull IVoiceInteractor interactor, @NonNull CancellationSignal cancellationSignal, + @NonNull RemoteCallback callback) { final ActivityClientRecord r = mActivities.get(activityToken); - if (r != null) { - final int lifecycleState = r.getLifecycleState(); - if (lifecycleState < ON_START || lifecycleState >= ON_STOP) { - callback.sendResult(null); - return; - } - if (r.activity.mVoiceInteractor == null - || r.activity.mVoiceInteractor.mInteractor.asBinder() - != interactor.asBinder()) { - if (r.activity.mVoiceInteractor != null) { - r.activity.mVoiceInteractor.destroy(); - } - r.activity.mVoiceInteractor = new VoiceInteractor(interactor, r.activity, - r.activity, Looper.myLooper()); + if (r == null) { + callback.sendResult(null); + return; + } + final int lifecycleState = r.getLifecycleState(); + if (lifecycleState < ON_START || lifecycleState >= ON_STOP) { + callback.sendResult(null); + return; + } + if (r.activity.mVoiceInteractor == null + || r.activity.mVoiceInteractor.mInteractor.asBinder() + != interactor.asBinder()) { + if (r.activity.mVoiceInteractor != null) { + r.activity.mVoiceInteractor.destroy(); } - final List<DirectAction> actions = r.activity.onGetDirectActions(); + r.activity.mVoiceInteractor = new VoiceInteractor(interactor, r.activity, + r.activity, Looper.myLooper()); + } + r.activity.onGetDirectActions(cancellationSignal, (actions) -> { Preconditions.checkNotNull(actions); Preconditions.checkCollectionElementsNotNull(actions, "actions"); - if (actions != null && !actions.isEmpty()) { + if (!actions.isEmpty()) { final int actionCount = actions.size(); for (int i = 0; i < actionCount; i++) { final DirectAction action = actions.get(i); @@ -3521,9 +3582,10 @@ public final class ActivityThread extends ClientTransactionHandler { result.putParcelable(DirectAction.KEY_ACTIONS_LIST, new ParceledListSlice<>(actions)); callback.sendResult(result); + } else { + callback.sendResult(null); } - } - callback.sendResult(null); + }); } /** Performs an actions in the corresponding activity */ @@ -3539,16 +3601,11 @@ public final class ActivityThread extends ClientTransactionHandler { return; } final Bundle nonNullArguments = (arguments != null) ? arguments : Bundle.EMPTY; - final WeakReference<RemoteCallback> weakCallback = new WeakReference<>(resultCallback); r.activity.onPerformDirectAction(actionId, nonNullArguments, cancellationSignal, - (b) -> { - final RemoteCallback strongCallback = weakCallback.get(); - if (strongCallback != null) { - strongCallback.sendResult(b); - } - }); + resultCallback::sendResult); + } else { + resultCallback.sendResult(null); } - resultCallback.sendResult(null); } public void handleTranslucentConversionComplete(IBinder token, boolean drawComplete) { diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index ac55c53d2257..66c438393bd6 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -141,7 +141,7 @@ oneway interface IApplicationThread { void setNetworkBlockSeq(long procStateSeq); void scheduleTransaction(in ClientTransaction transaction); void requestDirectActions(IBinder activityToken, IVoiceInteractor intractor, - in RemoteCallback callback); + in RemoteCallback cancellationCallback, in RemoteCallback callback); void performDirectAction(IBinder activityToken, String actionId, in Bundle arguments, in RemoteCallback cancellationCallback, in RemoteCallback resultCallback); diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 81b84e1f7070..cd8c7aea1bab 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -76,6 +76,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -171,6 +172,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall final WeakReference<VoiceInteractionSession> mWeakRef = new WeakReference<VoiceInteractionSession>(this); + // Registry of remote callbacks pending a reply with reply handles. + final Map<SafeResultListener, Consumer<Bundle>> mRemoteCallbacks = new ArrayMap<>(); + ICancellationSignal mKillCallback; final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() { @@ -1105,6 +1109,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } catch (RemoteException e) { /* ignore */ } + mKillCallback = null; } if (mInitialized) { mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener( @@ -1314,8 +1319,6 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } } - - /** * <p>Ask that a new assistant activity be started. This will create a new task in the * in activity manager: this means that @@ -1349,19 +1352,57 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * * @param activityId Ths activity id of the app to get the actions from. * @param resultExecutor The handler to receive the callback + * @param cancellationSignal A signal to cancel the operation in progress, + * or {@code null} if none. * @param callback The callback to receive the response */ public final void requestDirectActions(@NonNull ActivityId activityId, + @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor resultExecutor, @NonNull Consumer<List<DirectAction>> callback) { + Preconditions.checkNotNull(activityId); + Preconditions.checkNotNull(resultExecutor); + Preconditions.checkNotNull(callback); if (mToken == null) { throw new IllegalStateException("Can't call before onCreate()"); } + + if (cancellationSignal != null) { + cancellationSignal.throwIfCanceled(); + } + + final RemoteCallback cancellationCallback = (cancellationSignal != null) + ? new RemoteCallback(b -> { + if (b != null) { + final IBinder cancellation = b.getBinder( + VoiceInteractor.KEY_CANCELLATION_SIGNAL); + if (cancellation != null) { + cancellationSignal.setRemote(ICancellationSignal.Stub.asInterface( + cancellation)); + } + } + }) + : null; + try { mSystemService.requestDirectActions(mToken, activityId.getTaskId(), - activityId.getAssistToken(), new RemoteCallback(new DirectActionsReceiver( - Preconditions.checkNotNull(resultExecutor), - Preconditions.checkNotNull(callback)))); + activityId.getAssistToken(), cancellationCallback, + new RemoteCallback(createSafeResultListener((result) -> { + List<DirectAction> list; + if (result == null) { + list = Collections.emptyList(); + } else { + final ParceledListSlice<DirectAction> pls = result.getParcelable( + DirectAction.KEY_ACTIONS_LIST); + if (pls != null) { + final List<DirectAction> receivedList = pls.getList(); + list = (receivedList != null) ? receivedList : Collections.emptyList(); + } else { + list = Collections.emptyList(); + } + } + resultExecutor.execute(() -> callback.accept(list)); + }))); } catch (RemoteException e) { e.rethrowFromSystemServer(); } @@ -1390,8 +1431,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * @param resultExecutor The handler to receive the callback. * @param resultListener The callback to receive the response. * - * @see #requestDirectActions(ActivityId, Executor, Consumer) - * @see Activity#onGetDirectActions() + * @see #requestDirectActions(ActivityId, CancellationSignal, Executor, Consumer) + * @see Activity#onGetDirectActions(CancellationSignal, Consumer) */ public final void performDirectAction(@NonNull DirectAction action, @Nullable Bundle extras, @Nullable CancellationSignal cancellationSignal, @@ -1407,26 +1448,31 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall cancellationSignal.throwIfCanceled(); } - final RemoteCallback remoteCallback = new RemoteCallback(b -> { - if (b != null) { - final IBinder cancellation = b.getBinder(VoiceInteractor.KEY_CANCELLATION_SIGNAL); - if (cancellation != null) { - if (cancellationSignal != null) { - cancellationSignal.setRemote(ICancellationSignal.Stub.asInterface( - cancellation)); + final RemoteCallback cancellationCallback = (cancellationSignal != null) + ? new RemoteCallback(createSafeResultListener(b -> { + if (b != null) { + final IBinder cancellation = b.getBinder( + VoiceInteractor.KEY_CANCELLATION_SIGNAL); + if (cancellation != null) { + cancellationSignal.setRemote(ICancellationSignal.Stub.asInterface( + cancellation)); + } } - } else { - resultExecutor.execute(() -> resultListener.accept(b)); - } + })) + : null; + + final RemoteCallback resultCallback = new RemoteCallback(createSafeResultListener(b -> { + if (b != null) { + resultExecutor.execute(() -> resultListener.accept(b)); } else { resultExecutor.execute(() -> resultListener.accept(Bundle.EMPTY)); } - }); + })); try { mSystemService.performDirectAction(mToken, action.getId(), extras, - action.getTaskId(), action.getActivityId(), remoteCallback, - remoteCallback); + action.getTaskId(), action.getActivityId(), cancellationCallback, + resultCallback); } catch (RemoteException e) { e.rethrowFromSystemServer(); } @@ -1901,33 +1947,18 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } } - private static class DirectActionsReceiver implements RemoteCallback.OnResultListener { - - @NonNull - private final Executor mResultExecutor; - private final Consumer<List<DirectAction>> mCallback; - - DirectActionsReceiver(Executor resultExecutor, Consumer<List<DirectAction>> callback) { - mResultExecutor = resultExecutor; - mCallback = callback; + private SafeResultListener createSafeResultListener( + @NonNull Consumer<Bundle> consumer) { + synchronized (this) { + final SafeResultListener listener = new SafeResultListener(consumer, this); + mRemoteCallbacks.put(listener, consumer); + return listener; } + } - @Override - public void onResult(Bundle result) { - final List<DirectAction> list; - if (result == null) { - list = Collections.emptyList(); - } else { - final ParceledListSlice<DirectAction> pls = result.getParcelable( - DirectAction.KEY_ACTIONS_LIST); - if (pls != null) { - final List<DirectAction> receivedList = pls.getList(); - list = (receivedList != null) ? receivedList : Collections.emptyList(); - } else { - list = Collections.emptyList(); - } - } - mResultExecutor.execute(() -> mCallback.accept(list)); + private Consumer<Bundle> removeSafeResultListener(@NonNull SafeResultListener listener) { + synchronized (this) { + return mRemoteCallbacks.remove(listener); } } @@ -2062,4 +2093,24 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall return result; } } + + private static class SafeResultListener implements RemoteCallback.OnResultListener { + private final @NonNull WeakReference<VoiceInteractionSession> mWeakSession; + + SafeResultListener(@NonNull Consumer<Bundle> action, + @NonNull VoiceInteractionSession session) { + mWeakSession = new WeakReference<>(session); + } + + @Override + public void onResult(Bundle result) { + final VoiceInteractionSession session = mWeakSession.get(); + if (session != null) { + final Consumer<Bundle> consumer = session.removeSafeResultListener(this); + if (consumer != null) { + consumer.accept(result); + } + } + } + } } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index fb5e006d4873..f462f5d2571d 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -163,7 +163,7 @@ interface IVoiceInteractionManagerService { * Requests a list of supported actions from a specific activity. */ void requestDirectActions(in IBinder token, int taskId, IBinder assistToken, - in RemoteCallback callback); + in RemoteCallback cancellationCallback, in RemoteCallback callback); /** * Requests performing an action from a specific activity. diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 1b63b7e702bd..36ed88fbe8d5 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -628,8 +628,8 @@ public class TransactionParcelTests { } @Override - public void requestDirectActions(IBinder activityToken, IVoiceInteractor intractor, - RemoteCallback callback) { + public void requestDirectActions(IBinder activityToken, IVoiceInteractor interactor, + RemoteCallback cancellationCallback, RemoteCallback resultCallback) { } @Override diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 5903005e39b0..e1ffb0f179f8 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -714,17 +714,19 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public void requestDirectActions(@NonNull IBinder token, int taskId, IBinder assistToken, - @NonNull RemoteCallback callback) { + public void requestDirectActions(@NonNull IBinder token, int taskId, + @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback, + @NonNull RemoteCallback resultCallback) { synchronized (this) { if (mImpl == null) { Slog.w(TAG, "requestDirectActions without running voice interaction service"); - callback.sendResult(null); + resultCallback.sendResult(null); return; } final long caller = Binder.clearCallingIdentity(); try { - mImpl.requestDirectActionsLocked(token, taskId, assistToken, callback); + mImpl.requestDirectActionsLocked(token, taskId, assistToken, + cancellationCallback, resultCallback); } finally { Binder.restoreCallingIdentity(caller); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 0d80e6060301..2a5b70bf77f2 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -263,7 +263,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } public void requestDirectActionsLocked(@NonNull IBinder token, int taskId, - IBinder assistToken, @NonNull RemoteCallback callback) { + @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback, + @NonNull RemoteCallback callback) { if (mActiveSession == null || token != mActiveSession.mToken) { Slog.w(TAG, "requestDirectActionsLocked does not match active session"); callback.sendResult(null); @@ -277,7 +278,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } else { try { tokens.getApplicationThread().requestDirectActions(tokens.getActivityToken(), - mActiveSession.mInteractor, callback); + mActiveSession.mInteractor, cancellationCallback, callback); } catch (RemoteException e) { Slog.w("Unexpected remote error", e); callback.sendResult(null); |