diff options
9 files changed, 180 insertions, 52 deletions
diff --git a/Android.bp b/Android.bp index 1c59e2b2cd03..415eff3db7d7 100644 --- a/Android.bp +++ b/Android.bp @@ -368,6 +368,7 @@ java_defaults { "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 90ceee61108e..6042b2fa4c32 100755 --- a/api/current.txt +++ b/api/current.txt @@ -39928,6 +39928,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<java.lang.String> onGetSupportedVoiceActions(java.util.Set<java.lang.String>); 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 e3d68a6cbd8b..24819a6785fb 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<String> voiceActions, + in IVoiceActionCheckCallback callback); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 0bbc07e8063e..e105fdf6cfb8 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,22 +78,42 @@ 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 ready() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onReady, VoiceInteractionService.this)); } - @Override public void shutdown() { - mHandler.sendEmptyMessage(MSG_SHUTDOWN); + + @Override + public void shutdown() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onShutdownInternal, VoiceInteractionService.this)); } - @Override public void soundModelsChanged() { - mHandler.sendEmptyMessage(MSG_SOUND_MODELS_CHANGED); + + @Override + public void soundModelsChanged() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onSoundModelsChangedInternal, + VoiceInteractionService.this)); } + @Override - public void launchVoiceAssistFromKeyguard() throws RemoteException { - mHandler.sendEmptyMessage(MSG_LAUNCH_VOICE_ASSIST_FROM_KEYGUARD); + public void launchVoiceAssistFromKeyguard() { + Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage( + VoiceInteractionService::onLaunchVoiceAssistFromKeyguard, + VoiceInteractionService.this)); } - }; - MyHandler mHandler; + @Override + public void getActiveServiceSupportedActions(List<String> voiceActions, + IVoiceActionCheckCallback callback) { + Handler.getMain().executeOrSendMessage( + PooledLambda.obtainMessage(VoiceInteractionService::onHandleVoiceActionCheck, + VoiceInteractionService.this, + voiceActions, + callback)); + } + }; IVoiceInteractionManagerService mSystemService; @@ -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. + * + * <p>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<String> onGetSupportedVoiceActions(@NonNull Set<String> voiceActions) { + return null; } @Override @@ -254,6 +266,18 @@ public class VoiceInteractionService extends Service { } } + private void onHandleVoiceActionCheck(List<String> voiceActions, + IVoiceActionCheckCallback callback) { + if (callback != null) { + try { + Set<String> voiceActionsSet = new ArraySet<>(voiceActions); + Set<String> 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 9171959537c8..0f8295ac5868 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<String> 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 000000000000..66ba93d73483 --- /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<String> voiceActions); +} diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index ff75a8b5fea4..5088ccae5c1f 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<String> 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 c5d6dc7da5a7..99ad1f4d6b50 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<String> 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 57e9f661a0b0..61d7d6cf45d2 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<String> 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(); |