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

Commit c69727d5 authored by Govinda Wasserman's avatar Govinda Wasserman Committed by android-build-merger
Browse files

Adds learned state to the Reminder Experience for Assistant Handles

am: 1f606b09

Change-Id: I9e23630e82a3cc4a060f906d9892cee148f522eb
parents c46253f8 1f606b09
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -133,5 +133,17 @@ public final class SystemUiDeviceConfigFlags {
    public static final String ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS =
            "assist_handles_shown_frequency_threshold_ms";

    /**
     * (long) How long, in milliseconds, for teaching behaviors to wait before considering the user
     * taught.
     */
    public static final String ASSIST_HANDLES_LEARN_TIME_MS = "assist_handles_learn_time_ms";

    /**
     * (int) How many times for teaching behaviors to see the user perform an action to consider it
     * taught.
     */
    public static final String ASSIST_HANDLES_LEARN_COUNT = "assist_handles_learn_count";

    private SystemUiDeviceConfigFlags() { }
}
+17 −28
Original line number Diff line number Diff line
@@ -16,11 +16,7 @@

package com.android.systemui.assist;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -37,7 +33,6 @@ import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.NavigationModeController;

import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@@ -51,18 +46,17 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac

    private static final String TAG = "AssistHandleBehavior";

    private static final boolean IS_DEBUG_DEVICE =
            Build.TYPE.toLowerCase(Locale.ROOT).contains("debug")
                    || Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");

    private static final String SHOWN_FREQUENCY_THRESHOLD_KEY =
            "ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS";
    private static final long DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(10);
    private static final String SHOW_AND_GO_DURATION_KEY = "ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS";
    private static final long DEFAULT_SHOW_AND_GO_DURATION_MS = TimeUnit.SECONDS.toMillis(3);
    private static final String BEHAVIOR_KEY = "behavior";
    private static final String SET_BEHAVIOR_ACTION =
            "com.android.systemui.SET_ASSIST_HANDLE_BEHAVIOR";

    /**
     * This is the default behavior that will be used once the system is up. It will be set once the
     * behavior dependencies are available. This ensures proper behavior lifecycle.
     */
    private static final AssistHandleBehavior DEFAULT_BEHAVIOR = AssistHandleBehavior.REMINDER_EXP;

    private final Context mContext;
    private final Handler mHandler;
@@ -71,6 +65,10 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac

    private boolean mHandlesShowing = false;
    private long mHandlesLastHiddenAt;
    /**
     * This should always be initialized as {@link AssistHandleBehavior#OFF} to ensure proper
     * behavior lifecycle.
     */
    private AssistHandleBehavior mCurrentBehavior = AssistHandleBehavior.OFF;
    private boolean mInGesturalMode;

@@ -95,7 +93,7 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
        setBehavior(DeviceConfig.getString(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE,
                mCurrentBehavior.toString()));
                DEFAULT_BEHAVIOR.toString()));
        DeviceConfig.addOnPropertyChangedListener(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                mHandler::post,
@@ -104,20 +102,6 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
                        setBehavior(value);
                    }
                });

        if (IS_DEBUG_DEVICE) {
            context.registerReceiver(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String behaviorString = intent.getExtras().getString(BEHAVIOR_KEY);
                    try {
                        setBehavior(AssistHandleBehavior.valueOf(behaviorString));
                    } catch (IllegalArgumentException e) {
                        Log.e(TAG, "Invalid behavior identifier: " + behaviorString);
                    }
                }
            }, new IntentFilter(SET_BEHAVIOR_ACTION));
        }
    }

    @Override
@@ -141,6 +125,10 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
        mHandler.post(() -> maybeShowHandles(/* ignoreThreshold = */ true));
    }

    void onAssistantGesturePerformed() {
        mCurrentBehavior.getController().onAssistantGesturePerformed();
    }

    void setBehavior(AssistHandleBehavior behavior) {
        if (mCurrentBehavior == behavior) {
            return;
@@ -233,6 +221,7 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac

    interface BehaviorController {
        void onModeActivated(Context context, AssistHandleCallbacks callbacks);
        void onModeDeactivated();
        default void onModeDeactivated() {}
        default void onAssistantGesturePerformed() {}
    }
}
+0 −5
Original line number Diff line number Diff line
@@ -27,9 +27,4 @@ final class AssistHandleOffBehavior implements BehaviorController {
    public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
        callbacks.hide();
    }

    @Override
    public void onModeDeactivated() {
        // Do nothing
    }
}
+103 −7
Original line number Diff line number Diff line
@@ -19,9 +19,13 @@ package com.android.systemui.assist;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.provider.Settings;

import androidx.annotation.Nullable;

import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.Dependency;
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -31,6 +35,8 @@ import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.StatusBarState;

import java.util.concurrent.TimeUnit;

/**
 * Assistant handle behavior that hides the handles when the phone is dozing or in immersive mode,
 * shows the handles when on lockscreen, and shows the handles temporarily when changing tasks or
@@ -38,6 +44,11 @@ import com.android.systemui.statusbar.StatusBarState;
 */
final class AssistHandleReminderExpBehavior implements BehaviorController {

    private static final String LEARNING_TIME_ELAPSED_KEY = "reminder_exp_learning_time_elapsed";
    private static final String LEARNING_EVENT_COUNT_KEY = "reminder_exp_learning_event_count";
    private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(3);
    private static final int DEFAULT_LEARNING_COUNT = 3;

    private final StatusBarStateController.StateListener mStatusBarStateListener =
            new StatusBarStateController.StateListener() {
                @Override
@@ -84,6 +95,15 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
    private int mRunningTaskId;
    private boolean mIsNavBarHidden;

    /** Whether user has learned the gesture. */
    private boolean mIsLearned;
    private long mLastLearningTimestamp;
    /** Uptime while in this behavior. */
    private long mLearningTimeElapsed;
    /** Number of successful Assistant invocations while in this behavior. */
    private int mLearningCount;

    @Nullable private Context mContext;
    @Nullable private AssistHandleCallbacks mAssistHandleCallbacks;

    AssistHandleReminderExpBehavior() {
@@ -94,6 +114,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {

    @Override
    public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
        mContext = context;
        mAssistHandleCallbacks = callbacks;
        mOnLockscreen = onLockscreen(mStatusBarStateController.getState());
        mIsDozing = mStatusBarStateController.isDozing();
@@ -102,17 +123,41 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
        mRunningTaskId = runningTaskInfo == null ? 0 : runningTaskInfo.taskId;
        mActivityManagerWrapper.registerTaskStackListener(mTaskStackChangeListener);
        mOverviewProxyService.addCallback(mOverviewProxyListener);
        callbackForCurrentState();

        mLearningTimeElapsed = Settings.Secure.getLong(
                context.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, /* default = */ 0);
        mLearningCount = Settings.Secure.getInt(
                context.getContentResolver(), LEARNING_EVENT_COUNT_KEY, /* default = */ 0);
        mLastLearningTimestamp = SystemClock.uptimeMillis();

        callbackForCurrentState(/* justUnlocked = */ false);
    }

    @Override
    public void onModeDeactivated() {
        mAssistHandleCallbacks = null;
        if (mContext != null) {
            Settings.Secure.putLong(
                    mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed);
            Settings.Secure.putInt(
                    mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, mLearningCount);
            mContext = null;
        }
        mStatusBarStateController.removeCallback(mStatusBarStateListener);
        mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackChangeListener);
        mOverviewProxyService.removeCallback(mOverviewProxyListener);
    }

    @Override
    public void onAssistantGesturePerformed() {
        if (mContext == null) {
            return;
        }

        Settings.Secure.putLong(
                mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, ++mLearningCount);
    }

    private static boolean isNavBarHidden(int sysuiStateFlags) {
        return (sysuiStateFlags & QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
    }
@@ -124,7 +169,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
        }

        mOnLockscreen = onLockscreen;
        callbackForCurrentState();
        callbackForCurrentState(!onLockscreen);
    }

    private void handleDozingChanged(boolean isDozing) {
@@ -133,7 +178,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
        }

        mIsDozing = isDozing;
        callbackForCurrentState();
        callbackForCurrentState(/* justUnlocked = */ false);
    }

    private void handleTaskStackTopChanged(int taskId) {
@@ -142,7 +187,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
        }

        mRunningTaskId = taskId;
        callbackForCurrentState();
        callbackForCurrentState(/* justUnlocked = */ false);
    }

    private void handleSystemUiStateChanged(int sysuiStateFlags) {
@@ -152,11 +197,11 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
        }

        mIsNavBarHidden = isNavBarHidden;
        callbackForCurrentState();
        callbackForCurrentState(/* justUnlocked = */ false);
    }

    private void handleOverviewShown() {
        callbackForCurrentState();
        callbackForCurrentState(/* justUnlocked = */ false);
    }

    private boolean onLockscreen(int statusBarState) {
@@ -164,7 +209,29 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
                || statusBarState == StatusBarState.SHADE_LOCKED;
    }

    private void callbackForCurrentState() {
    private void callbackForCurrentState(boolean justUnlocked) {
        updateLearningStatus();

        if (mIsLearned) {
            callbackForLearnedState(justUnlocked);
        } else {
            callbackForUnlearnedState();
        }
    }

    private void callbackForLearnedState(boolean justUnlocked) {
        if (mAssistHandleCallbacks == null) {
            return;
        }

        if (mIsDozing || mIsNavBarHidden || mOnLockscreen) {
            mAssistHandleCallbacks.hide();
        } else if (justUnlocked) {
            mAssistHandleCallbacks.showAndGo();
        }
    }

    private void callbackForUnlearnedState() {
        if (mAssistHandleCallbacks == null) {
            return;
        }
@@ -177,4 +244,33 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
            mAssistHandleCallbacks.showAndGo();
        }
    }

    private void updateLearningStatus() {
        if (mContext == null) {
            return;
        }

        long currentTimestamp = SystemClock.uptimeMillis();
        mLearningTimeElapsed += currentTimestamp - mLastLearningTimestamp;
        mLastLearningTimestamp = currentTimestamp;
        Settings.Secure.putLong(
                mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed);

        mIsLearned =
                mLearningCount >= getLearningCount() || mLearningTimeElapsed >= getLearningTimeMs();
    }

    private long getLearningTimeMs() {
        return DeviceConfig.getLong(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_TIME_MS,
                DEFAULT_LEARNING_TIME_MS);
    }

    private int getLearningCount() {
        return DeviceConfig.getInt(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_COUNT,
                DEFAULT_LEARNING_COUNT);
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -246,13 +246,17 @@ public class AssistManager implements ConfigurationChangedReceiver {
        if (args == null) {
            args = new Bundle();
        }
        int invocationType = args.getInt(INVOCATION_TYPE_KEY, 0);
        if (invocationType == INVOCATION_TYPE_GESTURE) {
            mHandleController.onAssistantGesturePerformed();
        }
        args.putInt(INVOCATION_PHONE_STATE_KEY, mPhoneStateMonitor.getPhoneState());
        args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.uptimeMillis());
        // Logs assistant start with invocation type.
        MetricsLogger.action(
                new LogMaker(MetricsEvent.ASSISTANT)
                        .setType(MetricsEvent.TYPE_OPEN).setSubtype(
                        args.getInt(INVOCATION_TYPE_KEY)));
                        invocationType));
        startAssistInternal(args, assistComponent, isService);
    }