Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 625f9810 authored by Felix Oghina's avatar Felix Oghina
Browse files

[contextualsearch] implement assist data request

Test: added cts
Bug: 309657924
Change-Id: Ic13f20104f6a083ad4dad1f0e3a6e31529b16392
parent 0e75605d
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,8 @@ public final class CallbackToken implements Parcelable {
     * invocations of this method will result in {@link OutcomeReceiver#onError} being called with
     * invocations of this method will result in {@link OutcomeReceiver#onError} being called with
     * an {@link IllegalAccessException}.
     * an {@link IllegalAccessException}.
     *
     *
     * Note that the callback could be invoked multiple times, e.g. in the case of split screen.
     *
     * @param executor The executor which will be used to invoke the callback.
     * @param executor The executor which will be used to invoke the callback.
     * @param callback The callback which will be used to return {@link ContextualSearchState}
     * @param callback The callback which will be used to return {@link ContextualSearchState}
     *                 if/when it is available via {@link OutcomeReceiver#onResult}. It will also be
     *                 if/when it is available via {@link OutcomeReceiver#onResult}. It will also be
+99 −11
Original line number Original line Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.contextualsearch;
package com.android.server.contextualsearch;


import static android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH;
import static android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH;
import static android.app.AppOpsManager.OP_ASSIST_SCREENSHOT;
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.content.Context.CONTEXTUAL_SEARCH_SERVICE;
import static android.content.Context.CONTEXTUAL_SEARCH_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
@@ -24,11 +26,17 @@ import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;


import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;

import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.contextualsearch.CallbackToken;
import android.app.contextualsearch.CallbackToken;
import android.app.contextualsearch.ContextualSearchManager;
import android.app.contextualsearch.ContextualSearchManager;
import android.app.contextualsearch.ContextualSearchState;
import android.app.contextualsearch.ContextualSearchState;
@@ -37,6 +45,7 @@ import android.app.contextualsearch.IContextualSearchManager;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Bitmap;
import android.os.Binder;
import android.os.Binder;
@@ -49,15 +58,19 @@ import android.os.ParcelableException;
import android.os.Process;
import android.os.Process;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCallback;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
import android.view.IWindowManager;
import android.window.ScreenCapture;
import android.window.ScreenCapture;


import com.android.internal.R;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService;
import com.android.server.am.AssistDataRequester;
import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks;
import com.android.server.wm.ActivityAssistInfo;
import com.android.server.wm.ActivityAssistInfo;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -68,19 +81,66 @@ import java.util.List;
import java.util.Objects;
import java.util.Objects;


public class ContextualSearchManagerService extends SystemService {
public class ContextualSearchManagerService extends SystemService {

    private static final String TAG = ContextualSearchManagerService.class.getSimpleName();
    private static final int MSG_RESET_TEMPORARY_PACKAGE = 0;
    private static final int MSG_RESET_TEMPORARY_PACKAGE = 0;
    private static final int MAX_TEMP_PACKAGE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
    private static final int MAX_TEMP_PACKAGE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes

    private final Context mContext;
    private final Context mContext;
    private final ActivityTaskManagerInternal mAtmInternal;
    private final ActivityTaskManagerInternal mAtmInternal;
    private final PackageManagerInternal mPackageManager;
    private final WindowManagerInternal mWmInternal;
    private final WindowManagerInternal mWmInternal;
    private final DevicePolicyManagerInternal mDpmInternal;
    private final DevicePolicyManagerInternal mDpmInternal;
    private final Object mLock = new Object();
    private final AssistDataRequester mAssistDataRequester;


    private Handler mTemporaryHandler;
    private final AssistDataRequesterCallbacks mAssistDataCallbacks =
            new AssistDataRequesterCallbacks() {
                @Override
                public boolean canHandleReceivedAssistDataLocked() {
                    synchronized (mLock) {
                        return mStateCallback != null;
                    }
                }


                @Override
                public void onAssistDataReceivedLocked(
                        final Bundle data,
                        final int activityIndex,
                        final int activityCount) {
                    final IContextualSearchCallback callback;
                    synchronized (mLock) {
                        callback = mStateCallback;
                    }

                    if (callback != null) {
                        try {
                            callback.onResult(new ContextualSearchState(
                                    data.getParcelable(ASSIST_KEY_STRUCTURE, AssistStructure.class),
                                    data.getParcelable(ASSIST_KEY_CONTENT, AssistContent.class),
                                    data));
                        } catch (RemoteException e) {
                            Log.e(TAG, "Error invoking ContextualSearchCallback", e);
                        }
                    } else {
                        Log.w(TAG, "Callback went away!");
                    }
                }

                @Override
                public void onAssistRequestCompleted() {
                    synchronized (mLock) {
                        mStateCallback = null;
                    }
                }
            };

    @GuardedBy("this")
    private Handler mTemporaryHandler;
    @GuardedBy("this")
    @GuardedBy("this")
    private String mTemporaryPackage = null;
    private String mTemporaryPackage = null;
    private static final String TAG = ContextualSearchManagerService.class.getSimpleName();

    @GuardedBy("mLock")
    private IContextualSearchCallback mStateCallback;


    public ContextualSearchManagerService(@NonNull Context context) {
    public ContextualSearchManagerService(@NonNull Context context) {
        super(context);
        super(context);
@@ -88,8 +148,14 @@ public class ContextualSearchManagerService extends SystemService {
        mContext = context;
        mContext = context;
        mAtmInternal = Objects.requireNonNull(
        mAtmInternal = Objects.requireNonNull(
                LocalServices.getService(ActivityTaskManagerInternal.class));
                LocalServices.getService(ActivityTaskManagerInternal.class));
        mPackageManager = LocalServices.getService(PackageManagerInternal.class);
        mWmInternal = Objects.requireNonNull(LocalServices.getService(WindowManagerInternal.class));
        mWmInternal = Objects.requireNonNull(LocalServices.getService(WindowManagerInternal.class));
        mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
        mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
        mAssistDataRequester = new AssistDataRequester(
                mContext,
                IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)),
                mContext.getSystemService(AppOpsManager.class),
                mAssistDataCallbacks, mLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
    }
    }


    @Override
    @Override
@@ -178,18 +244,37 @@ public class ContextualSearchManagerService extends SystemService {
        launchIntent.putExtra(ContextualSearchManager.EXTRA_TOKEN, mToken);
        launchIntent.putExtra(ContextualSearchManager.EXTRA_TOKEN, mToken);
        boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed();
        boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed();
        final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities();
        final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities();
        final List<IBinder> activityTokens = new ArrayList<>(records.size());
        ArrayList<String> visiblePackageNames = new ArrayList<>();
        ArrayList<String> visiblePackageNames = new ArrayList<>();
        boolean isManagedProfileVisible = false;
        boolean isManagedProfileVisible = false;
        for (ActivityAssistInfo record : records) {
        for (ActivityAssistInfo record : records) {
            // Add the package name to the list only if assist data is allowed.
            // Add the package name to the list only if assist data is allowed.
            if (isAssistDataAllowed) {
            if (isAssistDataAllowed) {
                visiblePackageNames.add(record.getComponentName().getPackageName());
                visiblePackageNames.add(record.getComponentName().getPackageName());
                activityTokens.add(record.getActivityToken());
            }
            }
            if (mDpmInternal != null
            if (mDpmInternal != null
                    && mDpmInternal.isUserOrganizationManaged(record.getUserId())) {
                    && mDpmInternal.isUserOrganizationManaged(record.getUserId())) {
                isManagedProfileVisible = true;
                isManagedProfileVisible = true;
            }
            }
        }
        }
        if (isAssistDataAllowed) {
            try {
                final String csPackage = Objects.requireNonNull(launchIntent.getPackage());
                final int csUid = mPackageManager.getPackageUid(csPackage, 0, 0);
                mAssistDataRequester.requestAssistData(
                        activityTokens,
                        /* fetchData */ true,
                        /* fetchScreenshot */ false,
                        /* allowFetchData */ true,
                        /* allowFetchScreenshot */ false,
                        csUid,
                        csPackage,
                        null);
            } catch (Exception e) {
                Log.e(TAG, "Could not request assist data", e);
            }
        }
        final ScreenCapture.ScreenshotHardwareBuffer shb;
        final ScreenCapture.ScreenshotHardwareBuffer shb;
        if (mWmInternal != null) {
        if (mWmInternal != null) {
            shb = mWmInternal.takeAssistScreenshot();
            shb = mWmInternal.takeAssistScreenshot();
@@ -264,6 +349,7 @@ public class ContextualSearchManagerService extends SystemService {
            synchronized (this) {
            synchronized (this) {
                if (DEBUG_USER) Log.d(TAG, "startContextualSearch");
                if (DEBUG_USER) Log.d(TAG, "startContextualSearch");
                enforcePermission("startContextualSearch");
                enforcePermission("startContextualSearch");
                mAssistDataRequester.cancel();
                mToken = new CallbackToken();
                mToken = new CallbackToken();
                // We get the launch intent with the system server's identity because the system
                // We get the launch intent with the system server's identity because the system
                // server has READ_FRAME_BUFFER permission to get the screenshot and because only
                // server has READ_FRAME_BUFFER permission to get the screenshot and because only
@@ -298,17 +384,19 @@ public class ContextualSearchManagerService extends SystemService {
                return;
                return;
            }
            }
            mToken = null;
            mToken = null;
            // Process data request
            synchronized (mLock) {
            try {
                mStateCallback = callback;
                callback.onResult(new ContextualSearchState(null, null, Bundle.EMPTY));
            } catch (RemoteException e) {
                Log.e(TAG, "Could not invoke onResult callback", e);
            }
            }
            mAssistDataRequester.processPendingAssistData();
        }
        }


        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
        public void onShellCommand(
                @Nullable FileDescriptor err, @NonNull String[] args,
                @Nullable FileDescriptor in,
                @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) {
                @Nullable FileDescriptor out,
                @Nullable FileDescriptor err,
                @NonNull String[] args,
                @Nullable ShellCallback callback,
                @NonNull ResultReceiver resultReceiver) {
            new ContextualSearchManagerShellCommand(ContextualSearchManagerService.this)
            new ContextualSearchManagerShellCommand(ContextualSearchManagerService.this)
                    .exec(this, in, out, err, args, callback, resultReceiver);
                    .exec(this, in, out, err, args, callback, resultReceiver);
        }
        }