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

Commit 29bb3a34 authored by Peter Li's avatar Peter Li Committed by lpeter
Browse files

Inform Assistant visible activity when the stage of activity lifecycle is invoked.

By the original design, we register the activity event in the
ActivityManagerService. After getting the activity event, we will
query current visible activities and report them to Assistant.
Assistant will start to get direct actions of those visible
activities. But sometimes they can not get the direct actions
due to the stage of activity lifecycle before onStart().

We change the logic to make sure that the stage of visible
activity that we reported to the Assistant is after onStart().

Bug: 235296082
Test: atest VoiceInteractionSessionVisibleActivityTest
Test: atest android.app.activity.ActivityThreadClientTest
Test: atest android.view.DisplayTest
Test: atest android.window.ConfigurationHelperTest
Test: atest android.window.SizeConfigurationBucketsTest
Change-Id: Ie439ff3706dab35e875c1eb995a67fa73aec4d76
parent 9891ad2d
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -87,11 +87,13 @@ import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.service.voice.VoiceInteractionSession;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -155,6 +157,7 @@ import android.window.WindowOnBackInvokedDispatcher;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
@@ -1602,6 +1605,25 @@ public class Activity extends ContextThemeWrapper
        return callbacks;
    }

    private void notifyVoiceInteractionManagerServiceActivityEvent(
            @VoiceInteractionSession.VoiceInteractionActivityEventType int type) {

        final IVoiceInteractionManagerService service =
                IVoiceInteractionManagerService.Stub.asInterface(
                        ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
        if (service == null) {
            Log.w(TAG, "notifyVoiceInteractionManagerServiceActivityEvent: Can not get "
                    + "VoiceInteractionManagerService");
            return;
        }

        try {
            service.notifyActivityEventChanged(mToken, type);
        } catch (RemoteException e) {
            // Empty
        }
    }

    /**
     * Called when the activity is starting.  This is where most initialization
     * should go: calling {@link #setContentView(int)} to inflate the
@@ -1877,6 +1899,9 @@ public class Activity extends ContextThemeWrapper
        mCalled = true;

        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_START);

        notifyVoiceInteractionManagerServiceActivityEvent(
                VoiceInteractionSession.VOICE_INTERACTION_ACTIVITY_EVENT_START);
    }

    /**
@@ -2020,6 +2045,12 @@ public class Activity extends ContextThemeWrapper
        final Window win = getWindow();
        if (win != null) win.makeActive();
        if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);

        // Because the test case "com.android.launcher3.jank.BinderTests#testPressHome" doesn't
        // allow any binder call in onResume, we call this method in onPostResume.
        notifyVoiceInteractionManagerServiceActivityEvent(
                VoiceInteractionSession.VOICE_INTERACTION_ACTIVITY_EVENT_RESUME);

        mCalled = true;
    }

@@ -2395,6 +2426,10 @@ public class Activity extends ContextThemeWrapper
        getAutofillClientController().onActivityPaused();

        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);

        notifyVoiceInteractionManagerServiceActivityEvent(
                VoiceInteractionSession.VOICE_INTERACTION_ACTIVITY_EVENT_PAUSE);

        mCalled = true;
    }

@@ -2624,6 +2659,9 @@ public class Activity extends ContextThemeWrapper

        getAutofillClientController().onActivityStopped(mIntent, mChangingConfigurations);
        mEnterAnimationComplete = false;

        notifyVoiceInteractionManagerServiceActivityEvent(
                VoiceInteractionSession.VOICE_INTERACTION_ACTIVITY_EVENT_STOP);
    }

    /**
+2 −3
Original line number Diff line number Diff line
@@ -746,10 +746,9 @@ public abstract class ActivityManagerInternal {
     */
    public interface VoiceInteractionManagerProvider {
        /**
         * Notifies the service when a high-level activity event has been changed, for example,
         * an activity was resumed or stopped.
         * Notifies the service when an activity is destroyed.
         */
        void notifyActivityEventChanged();
        void notifyActivityDestroyed(IBinder activityToken);
    }

    /**
+22 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -73,6 +74,8 @@ import com.android.internal.util.function.pooled.PooledLambda;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -146,6 +149,25 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
     */
    public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 1 << 7;

    /** @hide */
    public static final int VOICE_INTERACTION_ACTIVITY_EVENT_START = 1;
    /** @hide */
    public static final int VOICE_INTERACTION_ACTIVITY_EVENT_RESUME = 2;
    /** @hide */
    public static final int VOICE_INTERACTION_ACTIVITY_EVENT_PAUSE = 3;
    /** @hide */
    public static final int VOICE_INTERACTION_ACTIVITY_EVENT_STOP = 4;

    /** @hide */
    @IntDef(prefix = { "VOICE_INTERACTION_ACTIVITY_EVENT_" }, value = {
            VOICE_INTERACTION_ACTIVITY_EVENT_START,
            VOICE_INTERACTION_ACTIVITY_EVENT_RESUME,
            VOICE_INTERACTION_ACTIVITY_EVENT_PAUSE,
            VOICE_INTERACTION_ACTIVITY_EVENT_STOP
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface VoiceInteractionActivityEventType{}

    final Context mContext;
    final HandlerCaller mHandlerCaller;

+18 −7
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.internal.app;

import android.content.ComponentName;
import android.content.Intent;
import android.hardware.soundtrigger.KeyphraseMetadata;
import android.hardware.soundtrigger.SoundTrigger;
import android.media.AudioFormat;
import android.media.permission.Identity;
import android.os.Bundle;
@@ -25,18 +27,17 @@ import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.SharedMemory;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VisibleActivityInfo;

import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.IVoiceInteractionSessionListener;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractionSoundTriggerSession;
import android.hardware.soundtrigger.KeyphraseMetadata;
import android.hardware.soundtrigger.SoundTrigger;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import com.android.internal.app.IVoiceInteractor;

interface IVoiceInteractionManagerService {
    void showSession(in Bundle sessionArgs, int flags, String attributionTag);
@@ -303,4 +304,14 @@ interface IVoiceInteractionManagerService {
     * Notifies when the session window is shown or hidden.
     */
    void setSessionWindowVisible(in IBinder token, boolean visible);

    /**
     * Notifies when the Activity lifecycle event changed.
     *
     * @param activityToken The token of activity.
     * @param type The type of lifecycle event of the activity lifecycle.
     */
    oneway void notifyActivityEventChanged(
            in IBinder activityToken,
            int type);
}
+7 −4
Original line number Diff line number Diff line
@@ -2934,10 +2934,13 @@ public class ActivityManagerService extends IActivityManager.Stub
                || event == Event.ACTIVITY_DESTROYED)) {
            contentCaptureService.notifyActivityEvent(userId, activity, event);
        }
        // TODO(b/201234353): Move the logic to client side.
        if (mVoiceInteractionManagerProvider != null && (event == Event.ACTIVITY_PAUSED
                || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED)) {
            mVoiceInteractionManagerProvider.notifyActivityEventChanged();
        // Currently we have move most of logic to the client side. When the activity lifecycle
        // event changed, the client side will notify the VoiceInteractionManagerService. But
        // when the application process died, the VoiceInteractionManagerService will miss the
        // activity lifecycle event changed, so we still need ACTIVITY_DESTROYED event here to
        // know if the activity has been destroyed.
        if (mVoiceInteractionManagerProvider != null && event == Event.ACTIVITY_DESTROYED) {
            mVoiceInteractionManagerProvider.notifyActivityDestroyed(appToken);
        }
    }
Loading