Fix onHandleAssist behaviour when showSession is called with flags = 0
The code to handle voice interaction sessions had two problems: 1. it was not handling correctly the case where VoiceInteractionSessionConnection.showLocked was called before a session started, without requiring any assist data (flags = 0). Now, when the session is set in VoiceInteractionSessionConnection, the pending `onHandleAssist` are called. 2. AssistState delivered with `onHandleAssist` had the wrong IBinder inside ActivityId. it contained ActivityRecord.appToken, but to work properly ActivityRecord.assistToken was required. Tests have been updated to catch this (atest CtsVoiceInteractionTestCases). Bug: 178020517 Test: atest CtsAssistTestCases Test: atest CtsVoiceInteractionTestCases Change-Id: Id10937f0655d6837ccb85250c369bdeccd261ed8
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 com.android.server.wm;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
* Class needed to expose some {@link ActivityRecord} fields in order to provide
|
||||
* {@link android.service.voice.VoiceInteractionSession#onHandleAssist(AssistState)}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class ActivityAssistInfo {
|
||||
private final IBinder mActivityToken;
|
||||
private final IBinder mAssistToken;
|
||||
private final int mTaskId;
|
||||
|
||||
public ActivityAssistInfo(ActivityRecord activityRecord) {
|
||||
this.mActivityToken = activityRecord.appToken;
|
||||
this.mAssistToken = activityRecord.assistToken;
|
||||
this.mTaskId = activityRecord.getTask().mTaskId;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public IBinder getActivityToken() {
|
||||
return mActivityToken;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public IBinder getAssistToken() {
|
||||
return mAssistToken;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getTaskId() {
|
||||
return mTaskId;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@ import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.service.voice.IVoiceInteractionSession;
|
||||
import android.util.Pair;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.window.TaskSnapshot;
|
||||
|
||||
@@ -166,7 +165,7 @@ public abstract class ActivityTaskManagerInternal {
|
||||
* Returns the top activity from each of the currently visible root tasks, and the related task
|
||||
* id. The first entry will be the focused activity.
|
||||
*/
|
||||
public abstract List<Pair<IBinder, Integer>> getTopVisibleActivities();
|
||||
public abstract List<ActivityAssistInfo> getTopVisibleActivities();
|
||||
|
||||
/**
|
||||
* Returns whether {@code uid} has any resumed activity.
|
||||
|
||||
@@ -215,7 +215,6 @@ import android.text.format.TimeMigrationUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TimeUtils;
|
||||
@@ -5075,7 +5074,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pair<IBinder, Integer>> getTopVisibleActivities() {
|
||||
public List<ActivityAssistInfo> getTopVisibleActivities() {
|
||||
synchronized (mGlobalLock) {
|
||||
return mRootWindowContainer.getTopVisibleActivities();
|
||||
}
|
||||
|
||||
@@ -1817,8 +1817,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
* @return a list of pairs, containing activities and their task id which are the top ones in
|
||||
* each visible root task. The first entry will be the focused activity.
|
||||
*/
|
||||
List<Pair<IBinder, Integer>> getTopVisibleActivities() {
|
||||
final ArrayList<Pair<IBinder, Integer>> topVisibleActivities = new ArrayList<>();
|
||||
List<ActivityAssistInfo> getTopVisibleActivities() {
|
||||
final ArrayList<ActivityAssistInfo> topVisibleActivities = new ArrayList<>();
|
||||
final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
|
||||
// Traverse all displays.
|
||||
forAllRootTasks(rootTask -> {
|
||||
@@ -1826,8 +1826,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
if (rootTask.shouldBeVisible(null /* starting */)) {
|
||||
final ActivityRecord top = rootTask.getTopNonFinishingActivity();
|
||||
if (top != null) {
|
||||
Pair<IBinder, Integer> visibleActivity = new Pair<>(top.appToken,
|
||||
top.getTask().mTaskId);
|
||||
ActivityAssistInfo visibleActivity = new ActivityAssistInfo(top);
|
||||
if (rootTask == topFocusedRootTask) {
|
||||
topVisibleActivities.add(0, visibleActivity);
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
"exclude-annotation": "androidx.test.filters.FlakyTest"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CtsAssistTestCases",
|
||||
"options": [
|
||||
{
|
||||
"exclude-annotation": "androidx.test.filters.FlakyTest"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import android.service.voice.IVoiceInteractionSession;
|
||||
import android.service.voice.VoiceInteractionService;
|
||||
import android.service.voice.VoiceInteractionServiceInfo;
|
||||
import android.system.OsConstants;
|
||||
import android.util.Pair;
|
||||
import android.util.PrintWriterPrinter;
|
||||
import android.util.Slog;
|
||||
import android.view.IWindowManager;
|
||||
@@ -60,6 +59,7 @@ import com.android.internal.app.IVoiceActionCheckCallback;
|
||||
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
|
||||
import com.android.internal.app.IVoiceInteractor;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.wm.ActivityAssistInfo;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal.ActivityTokens;
|
||||
|
||||
@@ -187,24 +187,23 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
|
||||
mSessionComponentName, mUser, mContext, this,
|
||||
mInfo.getServiceInfo().applicationInfo.uid, mHandler);
|
||||
}
|
||||
List<Pair<IBinder, Integer>> allVisibleActivities =
|
||||
List<ActivityAssistInfo> allVisibleActivities =
|
||||
LocalServices.getService(ActivityTaskManagerInternal.class)
|
||||
.getTopVisibleActivities();
|
||||
|
||||
List<Pair<IBinder, Integer>> visibleActivities = null;
|
||||
List<ActivityAssistInfo> visibleActivities = null;
|
||||
if (activityToken != null) {
|
||||
visibleActivities = new ArrayList();
|
||||
int activitiesCount = allVisibleActivities.size();
|
||||
for (int i = 0; i < activitiesCount; i++) {
|
||||
if (allVisibleActivities.get(i).first == activityToken) {
|
||||
visibleActivities.add(
|
||||
new Pair<>(activityToken, allVisibleActivities.get(i).second));
|
||||
ActivityAssistInfo info = allVisibleActivities.get(i);
|
||||
if (info.getActivityToken() == activityToken) {
|
||||
visibleActivities.add(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visibleActivities = LocalServices.getService(ActivityTaskManagerInternal.class)
|
||||
.getTopVisibleActivities();
|
||||
visibleActivities = allVisibleActivities;
|
||||
}
|
||||
return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback,
|
||||
visibleActivities);
|
||||
|
||||
@@ -56,7 +56,6 @@ import android.service.voice.IVoiceInteractionSession;
|
||||
import android.service.voice.IVoiceInteractionSessionService;
|
||||
import android.service.voice.VoiceInteractionService;
|
||||
import android.service.voice.VoiceInteractionSession;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.view.IWindowManager;
|
||||
|
||||
@@ -68,6 +67,7 @@ import com.android.server.am.AssistDataRequester;
|
||||
import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
import com.android.server.uri.UriGrantsManagerInternal;
|
||||
import com.android.server.wm.ActivityAssistInfo;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -102,6 +102,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
|
||||
IVoiceInteractionSession mSession;
|
||||
IVoiceInteractor mInteractor;
|
||||
ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>();
|
||||
private List<ActivityAssistInfo> mPendingHandleAssistWithoutData = new ArrayList<>();
|
||||
AssistDataRequester mAssistDataRequester;
|
||||
|
||||
IVoiceInteractionSessionShowCallback mShowCallback =
|
||||
@@ -192,7 +193,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
|
||||
|
||||
public boolean showLocked(Bundle args, int flags, int disabledContext,
|
||||
IVoiceInteractionSessionShowCallback showCallback,
|
||||
List<Pair<IBinder, Integer>> topActivities) {
|
||||
List<ActivityAssistInfo> topActivities) {
|
||||
if (mBound) {
|
||||
if (!mFullyBound) {
|
||||
mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
|
||||
@@ -216,7 +217,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
|
||||
int topActivitiesCount = topActivities.size();
|
||||
final ArrayList<IBinder> topActivitiesToken = new ArrayList<>(topActivitiesCount);
|
||||
for (int i = 0; i < topActivitiesCount; i++) {
|
||||
topActivitiesToken.add(topActivities.get(i).first);
|
||||
topActivitiesToken.add(topActivities.get(i).getActivityToken());
|
||||
}
|
||||
mAssistDataRequester.requestAssistData(topActivitiesToken,
|
||||
fetchData,
|
||||
@@ -243,8 +244,16 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
|
||||
} else {
|
||||
doHandleAssistWithoutData(topActivities);
|
||||
}
|
||||
} else if (showCallback != null) {
|
||||
mPendingShowCallbacks.add(showCallback);
|
||||
} else {
|
||||
if (showCallback != null) {
|
||||
mPendingShowCallbacks.add(showCallback);
|
||||
}
|
||||
if (!assistDataRequestNeeded) {
|
||||
// If no data are required we are not passing trough mAssistDataRequester. As
|
||||
// a consequence, when a new session is delivered it is needed to process those
|
||||
// requests manually.
|
||||
mPendingHandleAssistWithoutData = topActivities;
|
||||
}
|
||||
}
|
||||
mCallback.onSessionShown(this);
|
||||
return true;
|
||||
@@ -258,17 +267,17 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
|
||||
return false;
|
||||
}
|
||||
|
||||
private void doHandleAssistWithoutData(List<Pair<IBinder, Integer>> topActivities) {
|
||||
private void doHandleAssistWithoutData(List<ActivityAssistInfo> topActivities) {
|
||||
final int activityCount = topActivities.size();
|
||||
for (int i = 0; i < activityCount; i++) {
|
||||
final Pair<IBinder, Integer> topActivity = topActivities.get(i);
|
||||
final IBinder activityId = topActivity.first;
|
||||
final int taskId = topActivity.second;
|
||||
final ActivityAssistInfo topActivity = topActivities.get(i);
|
||||
final IBinder assistToken = topActivity.getAssistToken();
|
||||
final int taskId = topActivity.getTaskId();
|
||||
final int activityIndex = i;
|
||||
try {
|
||||
mSession.handleAssist(
|
||||
taskId,
|
||||
activityId,
|
||||
assistToken,
|
||||
/* assistData = */ null,
|
||||
/* assistStructure = */ null,
|
||||
/* assistContent = */ null,
|
||||
@@ -468,6 +477,10 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
mAssistDataRequester.processPendingAssistData();
|
||||
if (!mPendingHandleAssistWithoutData.isEmpty()) {
|
||||
doHandleAssistWithoutData(mPendingHandleAssistWithoutData);
|
||||
mPendingHandleAssistWithoutData.clear();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user