From 21a353b701a913f3ff3813293124640a3c45c4ad Mon Sep 17 00:00:00 2001 From: jiayuzhou Date: Thu, 16 Aug 2018 16:09:43 -0700 Subject: [PATCH] Make Changes to VoiceInteraction API for supporting System checking an assistant voice action availability on AAE. Test: build and test on AAE. Bug: 110587280 Change-Id: If37036e0dbe021fee9c95caf7e450330ca24ae32 --- Android.bp | 1 + api/current.txt | 1 + .../voice/IVoiceInteractionService.aidl | 4 + .../voice/VoiceInteractionService.java | 128 +++++++++++------- .../com/android/internal/app/AssistUtils.java | 32 ++++- .../app/IVoiceActionCheckCallback.aidl | 21 +++ .../app/IVoiceInteractionManagerService.aidl | 8 ++ .../VoiceInteractionManagerService.java | 23 ++++ .../VoiceInteractionManagerServiceImpl.java | 20 +++ 9 files changed, 183 insertions(+), 55 deletions(-) create mode 100644 core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl diff --git a/Android.bp b/Android.bp index 759014ffc9368..bbee9c13fb02a 100644 --- a/Android.bp +++ b/Android.bp @@ -366,6 +366,7 @@ java_library { "core/java/com/android/internal/app/IAppOpsService.aidl", "core/java/com/android/internal/app/IBatteryStats.aidl", "core/java/com/android/internal/app/ISoundTriggerService.aidl", + "core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl", "core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl", "core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl", "core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl", diff --git a/api/current.txt b/api/current.txt index 4d692eee1dd36..16cd16d62fc88 100644 --- a/api/current.txt +++ b/api/current.txt @@ -39759,6 +39759,7 @@ package android.service.voice { method public int getDisabledShowContext(); method public static boolean isActiveService(android.content.Context, android.content.ComponentName); method public android.os.IBinder onBind(android.content.Intent); + method public java.util.Set onGetSupportedVoiceActions(java.util.Set); method public void onLaunchVoiceAssistFromKeyguard(); method public void onReady(); method public void onShutdown(); diff --git a/core/java/android/service/voice/IVoiceInteractionService.aidl b/core/java/android/service/voice/IVoiceInteractionService.aidl index e3d68a6cbd8b9..24819a6785fb7 100644 --- a/core/java/android/service/voice/IVoiceInteractionService.aidl +++ b/core/java/android/service/voice/IVoiceInteractionService.aidl @@ -16,6 +16,8 @@ package android.service.voice; +import com.android.internal.app.IVoiceActionCheckCallback; + /** * @hide */ @@ -24,4 +26,6 @@ oneway interface IVoiceInteractionService { void soundModelsChanged(); void shutdown(); void launchVoiceAssistFromKeyguard(); + void getActiveServiceSupportedActions(in List voiceActions, + in IVoiceActionCheckCallback callback); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 0bbc07e8063ec..e105fdf6cfb88 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -16,6 +16,8 @@ package android.service.voice; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.UnsupportedAppUsage; import android.app.Service; @@ -26,17 +28,22 @@ import android.hardware.soundtrigger.KeyphraseEnrollmentInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; -import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceInteractionManagerService; +import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import java.util.Set; /** * Top-level service of the current global voice interactor, which is providing @@ -71,23 +78,43 @@ public class VoiceInteractionService extends Service { public static final String SERVICE_META_DATA = "android.voice_interaction"; IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() { - @Override public void ready() { - mHandler.sendEmptyMessage(MSG_READY); - } - @Override public void shutdown() { - mHandler.sendEmptyMessage(MSG_SHUTDOWN); - } - @Override public void soundModelsChanged() { - mHandler.sendEmptyMessage(MSG_SOUND_MODELS_CHANGED); - } @Override - public void launchVoiceAssistFromKeyguard() throws RemoteException { - mHandler.sendEmptyMessage(MSG_LAUNCH_VOICE_ASSIST_FROM_KEYGUARD); + public void ready() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onReady, VoiceInteractionService.this)); + } + + @Override + public void shutdown() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onShutdownInternal, VoiceInteractionService.this)); + } + + @Override + public void soundModelsChanged() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onSoundModelsChangedInternal, + VoiceInteractionService.this)); + } + + @Override + public void launchVoiceAssistFromKeyguard() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onLaunchVoiceAssistFromKeyguard, + VoiceInteractionService.this)); + } + + @Override + public void getActiveServiceSupportedActions(List voiceActions, + IVoiceActionCheckCallback callback) { + Handler.getMain().executeOrSendMessage( + PooledLambda.obtainMessage(VoiceInteractionService::onHandleVoiceActionCheck, + VoiceInteractionService.this, + voiceActions, + callback)); } }; - MyHandler mHandler; - IVoiceInteractionManagerService mSystemService; private final Object mLock = new Object(); @@ -96,33 +123,6 @@ public class VoiceInteractionService extends Service { private AlwaysOnHotwordDetector mHotwordDetector; - static final int MSG_READY = 1; - static final int MSG_SHUTDOWN = 2; - static final int MSG_SOUND_MODELS_CHANGED = 3; - static final int MSG_LAUNCH_VOICE_ASSIST_FROM_KEYGUARD = 4; - - class MyHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_READY: - onReady(); - break; - case MSG_SHUTDOWN: - onShutdownInternal(); - break; - case MSG_SOUND_MODELS_CHANGED: - onSoundModelsChangedInternal(); - break; - case MSG_LAUNCH_VOICE_ASSIST_FROM_KEYGUARD: - onLaunchVoiceAssistFromKeyguard(); - break; - default: - super.handleMessage(msg); - } - } - } - /** * Called when a user has activated an affordance to launch voice assist from the Keyguard. * @@ -186,7 +186,7 @@ public class VoiceInteractionService extends Service { * be any combination of * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT - * VoiceInteractionSession.SHOW_WITH_SCREENSHOT} + * VoiceInteractionSession.SHOW_WITH_SCREENSHOT} * to request that the system generate and deliver assist data on the current foreground * app as part of showing the session UI. */ @@ -200,10 +200,22 @@ public class VoiceInteractionService extends Service { } } - @Override - public void onCreate() { - super.onCreate(); - mHandler = new MyHandler(); + /** + * Request to query for what extended voice actions this service supports. This method will + * be called when the system checks the supported actions of this + * {@link VoiceInteractionService}. Supported actions may be delivered to + * {@link VoiceInteractionSession} later to request a session to perform an action. + * + *

Voice actions are defined in support libraries and could vary based on platform context. + * For example, car related voice actions will be defined in car support libraries. + * + * @param voiceActions A set of checked voice actions. + * @return Returns a subset of checked voice actions. Additional voice actions in the + * returned set will be ignored. Returns null or empty set if no actions are supported. + */ + @Nullable + public Set onGetSupportedVoiceActions(@NonNull Set voiceActions) { + return null; } @Override @@ -254,6 +266,18 @@ public class VoiceInteractionService extends Service { } } + private void onHandleVoiceActionCheck(List voiceActions, + IVoiceActionCheckCallback callback) { + if (callback != null) { + try { + Set voiceActionsSet = new ArraySet<>(voiceActions); + Set resultSet = onGetSupportedVoiceActions(voiceActionsSet); + callback.onComplete(resultSet == null ? null : new ArrayList<>(resultSet)); + } catch (RemoteException e) { + } + } + } + /** * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale. * This instance must be retained and used by the client. @@ -289,12 +313,12 @@ public class VoiceInteractionService extends Service { } /** - * Checks if a given keyphrase and locale are supported to create an - * {@link AlwaysOnHotwordDetector}. - * - * @return true if the keyphrase and locale combination is supported, false otherwise. - * @hide - */ + * Checks if a given keyphrase and locale are supported to create an + * {@link AlwaysOnHotwordDetector}. + * + * @return true if the keyphrase and locale combination is supported, false otherwise. + * @hide + */ @UnsupportedAppUsage public final boolean isKeyphraseAndLocaleSupportedForHotword(String keyphrase, Locale locale) { if (mKeyphraseEnrollmentInfo == null) { diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java index 9171959537c87..0f8295ac58684 100644 --- a/core/java/com/android/internal/app/AssistUtils.java +++ b/core/java/com/android/internal/app/AssistUtils.java @@ -16,8 +16,7 @@ package com.android.internal.app; -import com.android.internal.R; - +import android.annotation.NonNull; import android.app.SearchManager; import android.content.ComponentName; import android.content.Context; @@ -32,6 +31,9 @@ import android.os.ServiceManager; import android.provider.Settings; import android.util.Log; +import java.util.ArrayList; +import java.util.Set; + /** * Utility method for dealing with the assistant aspects of * {@link com.android.internal.app.IVoiceInteractionManagerService IVoiceInteractionManagerService}. @@ -62,6 +64,30 @@ public class AssistUtils { return false; } + /** + * Checks the availability of a set of voice actions for the current active voice service. + * + * @param voiceActions A set of supported voice actions to be checked. + * @param callback The callback which will deliver a set of supported voice actions. If + * no voice actions are supported for the given voice action set, then null + * or empty set is provided. + */ + public void getActiveServiceSupportedActions(@NonNull Set voiceActions, + @NonNull IVoiceActionCheckCallback callback) { + try { + if (mVoiceInteractionManagerService != null) { + mVoiceInteractionManagerService + .getActiveServiceSupportedActions(new ArrayList<>(voiceActions), callback); + } + } catch (RemoteException e) { + Log.w(TAG, "Failed to call activeServiceSupportedActions", e); + try { + callback.onComplete(null); + } catch (RemoteException re) { + } + } + } + public void launchVoiceAssistFromKeyguard() { try { if (mVoiceInteractionManagerService != null) { @@ -157,7 +183,7 @@ public class AssistUtils { return getActiveServiceComponentName(); } final SearchManager searchManager = - (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); + (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); if (searchManager == null) { return null; } diff --git a/core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl b/core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl new file mode 100644 index 0000000000000..66ba93d734834 --- /dev/null +++ b/core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +oneway interface IVoiceActionCheckCallback { + void onComplete(in List voiceActions); +} diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index ff75a8b5fea42..5088ccae5c1f7 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Intent; import android.os.Bundle; +import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceInteractionSessionShowCallback; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.IVoiceInteractionSessionListener; @@ -143,4 +144,11 @@ interface IVoiceInteractionManagerService { * Register a voice interaction listener. */ void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener); + + /** + * Checks the availability of a set of voice actions for the current active voice service. + * Returns all supported voice actions. + */ + void getActiveServiceSupportedActions(in List voiceActions, + in IVoiceActionCheckCallback callback); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index c5d6dc7da5a7d..99ad1f4d6b50b 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -19,6 +19,8 @@ package com.android.server.voiceinteraction; import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManagerInternal; + +import com.android.internal.app.IVoiceActionCheckCallback; import com.android.server.wm.ActivityTaskManagerInternal; import android.app.AppGlobals; import android.content.ComponentName; @@ -1128,6 +1130,27 @@ public class VoiceInteractionManagerService extends SystemService { } } + @Override + public void getActiveServiceSupportedActions(List voiceActions, + IVoiceActionCheckCallback callback) { + enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); + synchronized (this) { + if (mImpl == null) { + try { + callback.onComplete(null); + } catch (RemoteException e) { + } + return; + } + final long caller = Binder.clearCallingIdentity(); + try { + mImpl.getActiveServiceSupportedActions(voiceActions, callback); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + } + public void onSessionShown() { synchronized (this) { final int size = mVoiceInteractionSessionListeners.beginBroadcast(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 57e9f661a0b02..61d7d6cf45d29 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -25,6 +25,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; + +import com.android.internal.app.IVoiceActionCheckCallback; import com.android.server.wm.ActivityTaskManagerInternal; import android.app.IActivityManager; import android.app.IActivityTaskManager; @@ -57,6 +59,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Set; class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback { final static String TAG = "VoiceInteractionServiceManager"; @@ -177,6 +180,23 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne activityTokens); } + public void getActiveServiceSupportedActions(List commands, + IVoiceActionCheckCallback callback) { + if (mService == null) { + Slog.w(TAG, "Not bound to voice interaction service " + mComponent); + try { + callback.onComplete(null); + } catch (RemoteException e) { + } + return; + } + try { + mService.getActiveServiceSupportedActions(commands, callback); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException while calling getActiveServiceSupportedActions", e); + } + } + public boolean hideSessionLocked() { if (mActiveSession != null) { return mActiveSession.hideLocked();