diff options
Diffstat (limited to 'core/java')
7 files changed, 422 insertions, 1 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 70bb132c7668..f8c8aa32a26e 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -652,4 +652,23 @@ public abstract class ActivityManagerInternal { public abstract int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options); + + /** + * Sets the provider to communicate between voice interaction manager service and + * ActivityManagerService. + */ + public abstract void setVoiceInteractionManagerProvider( + @Nullable VoiceInteractionManagerProvider provider); + + /** + * Provides the interface to communicate between voice interaction manager service and + * ActivityManagerService. + */ + public interface VoiceInteractionManagerProvider { + /** + * Notifies the service when a high-level activity event has been changed, for example, + * an activity was resumed or stopped. + */ + void notifyActivityEventChanged(); + } } diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl index c142a53e047e..59f1e8eed89c 100644 --- a/core/java/android/service/voice/IVoiceInteractionSession.aidl +++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl @@ -22,6 +22,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.os.IBinder; +import android.service.voice.VisibleActivityInfo; import com.android.internal.app.IVoiceInteractionSessionShowCallback; @@ -39,4 +40,5 @@ oneway interface IVoiceInteractionSession { void closeSystemDialogs(); void onLockscreenShown(); void destroy(); + void updateVisibleActivityInfo(in VisibleActivityInfo visibleActivityInfo, int type); } diff --git a/core/java/android/service/voice/VisibleActivityInfo.aidl b/core/java/android/service/voice/VisibleActivityInfo.aidl new file mode 100644 index 000000000000..34bd57c15456 --- /dev/null +++ b/core/java/android/service/voice/VisibleActivityInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 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 android.service.voice; + +parcelable VisibleActivityInfo; diff --git a/core/java/android/service/voice/VisibleActivityInfo.java b/core/java/android/service/voice/VisibleActivityInfo.java new file mode 100644 index 000000000000..139544c76a50 --- /dev/null +++ b/core/java/android/service/voice/VisibleActivityInfo.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2021 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 android.service.voice; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TestApi; +import android.os.CancellationSignal; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * The class is used to represent a visible activity information. The system provides this to + * services that need to know {@link android.service.voice.VoiceInteractionSession.ActivityId}. + */ +@DataClass( + genConstructor = false, + genEqualsHashCode = true, + genHiddenConstDefs = false, + genGetters = false, + genToString = true +) +public final class VisibleActivityInfo implements Parcelable { + + /** + * Indicates that it is a new visible activity. + * + * @hide + */ + public static final int TYPE_ACTIVITY_ADDED = 1; + + /** + * Indicates that it has become a invisible activity. + * + * @hide + */ + public static final int TYPE_ACTIVITY_REMOVED = 2; + + /** + * The identifier of the task this activity is in. + */ + private final int mTaskId; + + /** + * Token for targeting this activity for assist purposes. + */ + @NonNull + private final IBinder mAssistToken; + + /** @hide */ + @TestApi + public VisibleActivityInfo( + int taskId, + @NonNull IBinder assistToken) { + Objects.requireNonNull(assistToken); + mTaskId = taskId; + mAssistToken = assistToken; + } + + /** + * Returns the {@link android.service.voice.VoiceInteractionSession.ActivityId} of this + * visible activity which can be used to interact with an activity, for example through + * {@link VoiceInteractionSession#requestDirectActions(VoiceInteractionSession.ActivityId, + * CancellationSignal, Executor, Consumer)}. + */ + public @NonNull VoiceInteractionSession.ActivityId getActivityId() { + return new VoiceInteractionSession.ActivityId(mTaskId, mAssistToken); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/voice/VisibleActivityInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "VisibleActivityInfo { " + + "taskId = " + mTaskId + ", " + + "assistToken = " + mAssistToken + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(VisibleActivityInfo other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + VisibleActivityInfo that = (VisibleActivityInfo) o; + //noinspection PointlessBooleanExpression + return true + && mTaskId == that.mTaskId + && Objects.equals(mAssistToken, that.mAssistToken); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + mTaskId; + _hash = 31 * _hash + Objects.hashCode(mAssistToken); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mTaskId); + dest.writeStrongBinder(mAssistToken); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ VisibleActivityInfo(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int taskId = in.readInt(); + IBinder assistToken = (IBinder) in.readStrongBinder(); + + this.mTaskId = taskId; + this.mAssistToken = assistToken; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAssistToken); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<VisibleActivityInfo> CREATOR + = new Parcelable.Creator<VisibleActivityInfo>() { + @Override + public VisibleActivityInfo[] newArray(int size) { + return new VisibleActivityInfo[size]; + } + + @Override + public VisibleActivityInfo createFromParcel(@NonNull Parcel in) { + return new VisibleActivityInfo(in); + } + }; + + @DataClass.Generated( + time = 1632383555284L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/service/voice/VisibleActivityInfo.java", + inputSignatures = "public static final int TYPE_ACTIVITY_ADDED\npublic static final int TYPE_ACTIVITY_REMOVED\nprivate final int mTaskId\nprivate final @android.annotation.NonNull android.os.IBinder mAssistToken\npublic @android.annotation.NonNull android.service.voice.VoiceInteractionSession.ActivityId getActivityId()\nclass VisibleActivityInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genEqualsHashCode=true, genHiddenConstDefs=false, genGetters=false, genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java index c048286545c3..c80640910bc2 100644 --- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java +++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java @@ -22,7 +22,6 @@ import android.os.IBinder; import com.android.internal.annotations.Immutable; - /** * @hide * Private interface to the VoiceInteractionManagerService for use by ActivityManagerService. diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 725e20f2a74d..9db856a8762a 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -74,9 +74,11 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -177,6 +179,10 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall ICancellationSignal mKillCallback; + private final Map<VisibleActivityCallback, Executor> mVisibleActivityCallbacks = + new ArrayMap<>(); + private final List<VisibleActivityInfo> mVisibleActivityInfos = new ArrayList<>(); + final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() { @Override public IVoiceInteractorRequest startConfirmation(String callingPackage, @@ -352,6 +358,13 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall public void destroy() { mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY)); } + + @Override + public void updateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) { + mHandlerCaller.sendMessage( + mHandlerCaller.obtainMessageIO(MSG_UPDATE_VISIBLE_ACTIVITY_INFO, type, + visibleActivityInfo)); + } }; /** @@ -843,6 +856,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall static final int MSG_SHOW = 106; static final int MSG_HIDE = 107; static final int MSG_ON_LOCKSCREEN_SHOWN = 108; + static final int MSG_UPDATE_VISIBLE_ACTIVITY_INFO = 109; + static final int MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK = 110; + static final int MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK = 111; class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback { @Override @@ -928,6 +944,27 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall if (DEBUG) Log.d(TAG, "onLockscreenShown"); onLockscreenShown(); break; + case MSG_UPDATE_VISIBLE_ACTIVITY_INFO: + if (DEBUG) { + Log.d(TAG, "doUpdateVisibleActivityInfo: visibleActivityInfo=" + msg.obj + + " type=" + msg.arg1); + } + doUpdateVisibleActivityInfo((VisibleActivityInfo) msg.obj, msg.arg1); + break; + case MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK: + if (DEBUG) { + Log.d(TAG, "doRegisterVisibleActivityCallback"); + } + args = (SomeArgs) msg.obj; + doRegisterVisibleActivityCallback((Executor) args.arg1, + (VisibleActivityCallback) args.arg2); + break; + case MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK: + if (DEBUG) { + Log.d(TAG, "doUnregisterVisibleActivityCallback"); + } + doUnregisterVisibleActivityCallback((VisibleActivityCallback) msg.obj); + break; } if (args != null) { args.recycle(); @@ -1122,6 +1159,86 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } } + private void doUpdateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) { + + if (mVisibleActivityCallbacks.isEmpty()) { + return; + } + + switch (type) { + case VisibleActivityInfo.TYPE_ACTIVITY_ADDED: + informVisibleActivityChanged(visibleActivityInfo, type); + mVisibleActivityInfos.add(visibleActivityInfo); + break; + case VisibleActivityInfo.TYPE_ACTIVITY_REMOVED: + informVisibleActivityChanged(visibleActivityInfo, type); + mVisibleActivityInfos.remove(visibleActivityInfo); + break; + } + } + + private void doRegisterVisibleActivityCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull VisibleActivityCallback callback) { + if (mVisibleActivityCallbacks.containsKey(callback)) { + if (DEBUG) { + Log.d(TAG, "doRegisterVisibleActivityCallback: callback has registered"); + } + return; + } + + int preCallbackCount = mVisibleActivityCallbacks.size(); + mVisibleActivityCallbacks.put(callback, executor); + + if (preCallbackCount == 0) { + try { + mSystemService.startListeningVisibleActivityChanged(mToken); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } else { + for (int i = 0; i < mVisibleActivityInfos.size(); i++) { + final VisibleActivityInfo visibleActivityInfo = mVisibleActivityInfos.get(i); + executor.execute(() -> callback.onVisible(visibleActivityInfo)); + } + } + } + + private void doUnregisterVisibleActivityCallback(@NonNull VisibleActivityCallback callback) { + mVisibleActivityCallbacks.remove(callback); + + if (mVisibleActivityCallbacks.size() == 0) { + mVisibleActivityInfos.clear(); + try { + mSystemService.stopListeningVisibleActivityChanged(mToken); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + } + + private void informVisibleActivityChanged(VisibleActivityInfo visibleActivityInfo, int type) { + for (Map.Entry<VisibleActivityCallback, Executor> e : + mVisibleActivityCallbacks.entrySet()) { + final Executor executor = e.getValue(); + final VisibleActivityCallback visibleActivityCallback = e.getKey(); + + switch (type) { + case VisibleActivityInfo.TYPE_ACTIVITY_ADDED: + Binder.withCleanCallingIdentity(() -> { + executor.execute( + () -> visibleActivityCallback.onVisible(visibleActivityInfo)); + }); + break; + case VisibleActivityInfo.TYPE_ACTIVITY_REMOVED: + Binder.withCleanCallingIdentity(() -> { + executor.execute(() -> visibleActivityCallback.onInvisible( + visibleActivityInfo.getActivityId())); + }); + break; + } + } + } + void ensureWindowCreated() { if (mInitialized) { return; @@ -1926,6 +2043,45 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** + * Registers a callback that will be notified when visible activities have been changed. + * + * @param executor The handler to receive the callback. + * @param callback The callback to receive the response. + * + * @throws IllegalStateException if calling this method before onCreate(). + */ + public final void registerVisibleActivityCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull VisibleActivityCallback callback) { + if (DEBUG) { + Log.d(TAG, "registerVisibleActivityCallback"); + } + if (mToken == null) { + throw new IllegalStateException("Can't call before onCreate()"); + } + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + mHandlerCaller.sendMessage( + mHandlerCaller.obtainMessageOO(MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK, executor, + callback)); + } + + /** + * Unregisters the callback. + * + * @param callback The callback to receive the response. + */ + public final void unregisterVisibleActivityCallback(@NonNull VisibleActivityCallback callback) { + if (DEBUG) { + Log.d(TAG, "unregisterVisibleActivityCallback"); + } + Objects.requireNonNull(callback); + + mHandlerCaller.sendMessage( + mHandlerCaller.obtainMessageO(MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK, callback)); + } + + /** * Print the Service's state into the given stream. This gets invoked by * {@link VoiceInteractionSessionService} when its Service * {@link android.app.Service#dump} method is called. @@ -1975,6 +2131,17 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** + * Callback interface for receiving visible activity changes used for assistant usage. + */ + public interface VisibleActivityCallback { + /** Callback to inform that an activity has become visible. */ + default void onVisible(@NonNull VisibleActivityInfo activityInfo) {} + + /** Callback to inform that a visible activity has gone. */ + default void onInvisible(@NonNull ActivityId activityId) {} + } + + /** * Represents assist state captured when this session was started. * It contains the various assist data objects and a reference to * the source activity. diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index c8a4425409e8..998526209c72 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -272,4 +272,14 @@ interface IVoiceInteractionManagerService { void triggerHardwareRecognitionEventForTest( in SoundTrigger.KeyphraseRecognitionEvent event, in IHotwordRecognitionStatusCallback callback); + + /** + * Starts to listen the status of visible activity. + */ + void startListeningVisibleActivityChanged(in IBinder token); + + /** + * Stops to listen the status of visible activity. + */ + void stopListeningVisibleActivityChanged(in IBinder token); } |
