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

Commit 77d215b9 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 9434600 from d5a4b9e5 to tm-qpr2-release

Change-Id: I07c013ec90fe86a51c905b4aea0a3ef86409e92f
parents 4ce422f7 d5a4b9e5
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -115,4 +115,10 @@
    <!-- Components support to launch multiple instances into split-screen -->
    <string-array name="config_appsSupportMultiInstancesSplit">
    </string-array>

    <!-- Whether the extended restart dialog is enabled -->
    <bool name="config_letterboxIsRestartDialogEnabled">false</bool>

    <!-- Whether the additional education about reachability is enabled -->
    <bool name="config_letterboxIsReachabilityEducationEnabled">false</bool>
</resources>
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.wm.shell.compatui;

import android.content.Context;
import android.provider.DeviceConfig;

import androidx.annotation.NonNull;

import com.android.wm.shell.R;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.dagger.WMSingleton;

import javax.inject.Inject;

/**
 * Configuration flags for the CompatUX implementation
 */
@WMSingleton
public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedListener {

    static final String KEY_ENABLE_LETTERBOX_RESTART_DIALOG = "enable_letterbox_restart_dialog";

    static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION =
            "enable_letterbox_reachability_education";

    // Whether the extended restart dialog is enabled
    private boolean mIsRestartDialogEnabled;

    // Whether the additional education about reachability is enabled
    private boolean mIsReachabilityEducationEnabled;

    // Whether the extended restart dialog is enabled
    private boolean mIsRestartDialogOverrideEnabled;

    // Whether the additional education about reachability is enabled
    private boolean mIsReachabilityEducationOverrideEnabled;

    // Whether the extended restart dialog is allowed from backend
    private boolean mIsLetterboxRestartDialogAllowed;

    // Whether the additional education about reachability is allowed from backend
    private boolean mIsLetterboxReachabilityEducationAllowed;

    @Inject
    public CompatUIConfiguration(Context context, @ShellMainThread ShellExecutor mainExecutor) {
        mIsRestartDialogEnabled = context.getResources().getBoolean(
                R.bool.config_letterboxIsRestartDialogEnabled);
        mIsReachabilityEducationEnabled = context.getResources().getBoolean(
                R.bool.config_letterboxIsReachabilityEducationEnabled);
        mIsLetterboxRestartDialogAllowed = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG, false);
        mIsLetterboxReachabilityEducationAllowed = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION,
                false);
        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT, mainExecutor,
                this);
    }

    /**
     * @return {@value true} if the restart dialog is enabled.
     */
    boolean isRestartDialogEnabled() {
        return mIsRestartDialogOverrideEnabled || (mIsRestartDialogEnabled
                && mIsLetterboxRestartDialogAllowed);
    }

    /**
     * Enables/Disables the restart education dialog
     */
    void setIsRestartDialogOverrideEnabled(boolean enabled) {
        mIsRestartDialogOverrideEnabled = enabled;
    }

    /**
     * @return {@value true} if the reachability education is enabled.
     */
    boolean isReachabilityEducationEnabled() {
        return mIsReachabilityEducationOverrideEnabled || (mIsReachabilityEducationEnabled
                && mIsLetterboxReachabilityEducationAllowed);
    }

    /**
     * Enables/Disables the reachability education
     */
    void setIsReachabilityEducationOverrideEnabled(boolean enabled) {
        mIsReachabilityEducationOverrideEnabled = enabled;
    }

    @Override
    public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
        // TODO(b/263349751): Update flag and default value to true
        if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_RESTART_DIALOG)) {
            mIsLetterboxRestartDialogAllowed = DeviceConfig.getBoolean(
                    DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG,
                    false);
        }
        if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION)) {
            mIsLetterboxReachabilityEducationAllowed = DeviceConfig.getBoolean(
                    DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                    KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION, false);
        }
    }
}
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.wm.shell.compatui;

import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.sysui.ShellCommandHandler;

import java.io.PrintWriter;
import java.util.function.Consumer;

import javax.inject.Inject;

/**
 * Handles the shell commands for the CompatUX.
 *
 * <p> Use with {@code adb shell dumpsys activity service SystemUIService WMShell compatui
 * &lt;command&gt;}.
 */
@WMSingleton
public final class CompatUIShellCommandHandler implements
        ShellCommandHandler.ShellCommandActionHandler {

    private final CompatUIConfiguration mCompatUIConfiguration;
    private final ShellCommandHandler mShellCommandHandler;

    @Inject
    public CompatUIShellCommandHandler(ShellCommandHandler shellCommandHandler,
            CompatUIConfiguration compatUIConfiguration) {
        mShellCommandHandler = shellCommandHandler;
        mCompatUIConfiguration = compatUIConfiguration;
    }

    void onInit() {
        mShellCommandHandler.addCommandCallback("compatui", this, this);
    }

    @Override
    public boolean onShellCommand(String[] args, PrintWriter pw) {
        if (args.length != 2) {
            pw.println("Invalid command: " + args[0]);
            return false;
        }
        switch (args[0]) {
            case "restartDialogEnabled":
                return invokeOrError(args[1], pw,
                        mCompatUIConfiguration::setIsRestartDialogOverrideEnabled);
            case "reachabilityEducationEnabled":
                return invokeOrError(args[1], pw,
                        mCompatUIConfiguration::setIsReachabilityEducationOverrideEnabled);
            default:
                pw.println("Invalid command: " + args[0]);
                return false;
        }
    }

    @Override
    public void printShellCommandHelp(PrintWriter pw, String prefix) {
        pw.println(prefix + "restartDialogEnabled [0|false|1|true]");
        pw.println(prefix + "  Enable/Disable the restart education dialog for Size Compat Mode");
        pw.println(prefix + "reachabilityEducationEnabled [0|false|1|true]");
        pw.println(prefix
                + "  Enable/Disable the restart education dialog for letterbox reachability");
        pw.println(prefix + "  Disable the restart education dialog for letterbox reachability");
    }

    private static boolean invokeOrError(String input, PrintWriter pw,
            Consumer<Boolean> setter) {
        Boolean asBoolean = strToBoolean(input);
        if (asBoolean == null) {
            pw.println("Error: expected true, 1, false, 0.");
            return false;
        }
        setter.accept(asBoolean);
        return true;
    }

    // Converts a String to boolean if possible or it returns null otherwise
    private static Boolean strToBoolean(String str) {
        switch(str) {
            case "1":
            case "true":
                return true;
            case "0":
            case "false":
                return false;
        }
        return null;
    }
}
+23 −16
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

package com.android.wm.shell.compatui.letterboxedu;
package com.android.wm.shell.compatui;

import static com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
import static com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
@@ -38,10 +38,15 @@ import android.view.animation.Animation;
import com.android.internal.policy.TransitionAnimation;

/**
 * Controls the enter/exit animations of the letterbox education.
 * Controls the enter/exit a dialog.
 *
 * @param <T> The {@link DialogContainerSupplier} to use
 */
class LetterboxEduAnimationController {
    private static final String TAG = "LetterboxEduAnimation";
public class DialogAnimationController<T extends DialogContainerSupplier> {

    // The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
    // 204 is simply 255 * 0.8.
    static final int BACKGROUND_DIM_ALPHA = 204;

    // If shell transitions are enabled, startEnterAnimation will be called after all transitions
    // have finished, and therefore the start delay should be shorter.
@@ -49,6 +54,7 @@ class LetterboxEduAnimationController {

    private final TransitionAnimation mTransitionAnimation;
    private final String mPackageName;
    private final String mTag;
    @AnyRes
    private final int mAnimStyleResId;

@@ -57,23 +63,24 @@ class LetterboxEduAnimationController {
    @Nullable
    private Animator mBackgroundDimAnimator;

    LetterboxEduAnimationController(Context context) {
        mTransitionAnimation = new TransitionAnimation(context, /* debug= */ false, TAG);
    public DialogAnimationController(Context context, String tag) {
        mTransitionAnimation = new TransitionAnimation(context, /* debug= */ false, tag);
        mAnimStyleResId = (new ContextThemeWrapper(context,
                android.R.style.ThemeOverlay_Material_Dialog).getTheme()).obtainStyledAttributes(
                com.android.internal.R.styleable.Window).getResourceId(
                com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
        mPackageName = context.getPackageName();
        mTag = tag;
    }

    /**
     * Starts both background dim fade-in animation and the dialog enter animation.
     */
    void startEnterAnimation(@NonNull LetterboxEduDialogLayout layout, Runnable endCallback) {
    public void startEnterAnimation(@NonNull T layout, Runnable endCallback) {
        // Cancel any previous animation if it's still running.
        cancelAnimation();

        final View dialogContainer = layout.getDialogContainer();
        final View dialogContainer = layout.getDialogContainerView();
        mDialogAnimation = loadAnimation(WindowAnimation_windowEnterAnimation);
        if (mDialogAnimation == null) {
            endCallback.run();
@@ -86,8 +93,8 @@ class LetterboxEduAnimationController {
                    endCallback.run();
                }));

        mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(),
                /* endAlpha= */ LetterboxEduDialogLayout.BACKGROUND_DIM_ALPHA,
        mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDimDrawable(),
                /* endAlpha= */ BACKGROUND_DIM_ALPHA,
                mDialogAnimation.getDuration());
        mBackgroundDimAnimator.addListener(getDimAnimatorListener());

@@ -101,11 +108,11 @@ class LetterboxEduAnimationController {
    /**
     * Starts both the background dim fade-out animation and the dialog exit animation.
     */
    void startExitAnimation(@NonNull LetterboxEduDialogLayout layout, Runnable endCallback) {
    public void startExitAnimation(@NonNull T layout, Runnable endCallback) {
        // Cancel any previous animation if it's still running.
        cancelAnimation();

        final View dialogContainer = layout.getDialogContainer();
        final View dialogContainer = layout.getDialogContainerView();
        mDialogAnimation = loadAnimation(WindowAnimation_windowExitAnimation);
        if (mDialogAnimation == null) {
            endCallback.run();
@@ -119,8 +126,8 @@ class LetterboxEduAnimationController {
                    endCallback.run();
                }));

        mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(), /* endAlpha= */ 0,
                mDialogAnimation.getDuration());
        mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDimDrawable(),
                /* endAlpha= */ 0, mDialogAnimation.getDuration());
        mBackgroundDimAnimator.addListener(getDimAnimatorListener());

        dialogContainer.startAnimation(mDialogAnimation);
@@ -130,7 +137,7 @@ class LetterboxEduAnimationController {
    /**
     * Cancels all animations and resets the state of the controller.
     */
    void cancelAnimation() {
    public void cancelAnimation() {
        if (mDialogAnimation != null) {
            mDialogAnimation.cancel();
            mDialogAnimation = null;
@@ -145,7 +152,7 @@ class LetterboxEduAnimationController {
        Animation animation = mTransitionAnimation.loadAnimationAttr(mPackageName, mAnimStyleResId,
                animAttr, /* translucent= */ false);
        if (animation == null) {
            Log.e(TAG, "Failed to load animation " + animAttr);
            Log.e(mTag, "Failed to load animation " + animAttr);
        }
        return animation;
    }
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.wm.shell.compatui;

import android.graphics.drawable.Drawable;
import android.view.View;

/**
 * A component which can provide a {@link View} to use as a container for a Dialog
 */
public interface DialogContainerSupplier {

    /**
     * @return The {@link View} to use as a container for a Dialog
     */
    View getDialogContainerView();

    /**
     * @return The {@link Drawable} to use as background of the dialog.
     */
    Drawable getBackgroundDimDrawable();
}
Loading