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

Commit 6f007458 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Merge cherrypicks of ['googleplex-android-review.googlesource.com/23447960',...

Merge cherrypicks of ['googleplex-android-review.googlesource.com/23447960', 'googleplex-android-review.googlesource.com/24154592'] into sparse-10615697-L60900000962405601.
SPARSE_CHANGE: Ic437ff4d19cbd5764635f3007d99880622150f5b
SPARSE_CHANGE: Ic33dc94806b838a03a2203bdd5701a1eeaeeb7bf

Change-Id: I8eadeecea932cad65ff512b1dd944f1e2f0dcde4
parents 7a9fd859 5038853c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.wm.shell.startingsurface.IStartingWindowListener;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -477,6 +478,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
        });
    }

    /** Dump debug logs to bug report. */
    public void dump(@NonNull String prefix, @NonNull PrintWriter printWriter) {}

    /**
     * Content is everything on screen except the background and the floating view (if any).
     *
+9 −0
Original line number Diff line number Diff line
@@ -204,6 +204,8 @@ public class QuickstepLauncher extends Launcher {

    public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;

    protected static final String RING_APPEAR_ANIMATION_PREFIX = "RingAppearAnimation\t";

    private FixedContainerItems mAllAppsPredictions;
    private HotseatPredictionController mHotseatPredictionController;
    private DepthController mDepthController;
@@ -472,6 +474,10 @@ public class QuickstepLauncher extends Launcher {
    public void onDestroy() {
        mAppTransitionManager.onActivityDestroyed();
        if (mUnfoldTransitionProgressProvider != null) {
            if (FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
                SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
            }

            mUnfoldTransitionProgressProvider.destroy();
        }

@@ -1332,5 +1338,8 @@ public class QuickstepLauncher extends Launcher {
        if (recentsView != null) {
            recentsView.getSplitSelectController().dump(prefix, writer);
        }
        if (mAppTransitionManager != null) {
            mAppTransitionManager.dump(prefix + "\t" + RING_APPEAR_ANIMATION_PREFIX, writer);
        }
    }
}
+64 −1
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL
    private final NaturalRotationUnfoldProgressProvider mNaturalOrientationProgressProvider;
    private final UnfoldMoveFromCenterHotseatAnimator mUnfoldMoveFromCenterHotseatAnimator;
    private final UnfoldMoveFromCenterWorkspaceAnimator mUnfoldMoveFromCenterWorkspaceAnimator;
    private final TransitionStatusProvider mExternalTransitionStatusProvider =
            new TransitionStatusProvider();
    private PreemptiveUnfoldTransitionProgressProvider mPreemptiveProgressProvider = null;
    private Boolean mIsTablet = null;

@@ -88,6 +90,8 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL
                    unfoldTransitionProgressProvider);
        }

        unfoldTransitionProgressProvider.addCallback(mExternalTransitionStatusProvider);

        mUnfoldMoveFromCenterHotseatAnimator = new UnfoldMoveFromCenterHotseatAnimator(launcher,
                windowManager, rotationChangeProvider);
        mUnfoldMoveFromCenterWorkspaceAnimator = new UnfoldMoveFromCenterWorkspaceAnimator(launcher,
@@ -166,11 +170,26 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL
        }

        if (mIsTablet != null && dp.isTablet != mIsTablet) {
            if (dp.isTablet && SystemUiProxy.INSTANCE.get(mLauncher).isActive()) {
            // We should preemptively start the animation only if:
            // - We changed to the unfolded screen
            // - SystemUI IPC connection is alive, so we won't end up in a situation that we won't
            //   receive transition progress events from SystemUI later because there was no
            //   IPC connection established (e.g. because of SystemUI crash)
            // - SystemUI has not already sent unfold animation progress events. This might happen
            //   if Launcher was not open during unfold, in this case we receive the configuration
            //   change only after we went back to home screen and we don't want to start the
            //   animation in this case.
            if (dp.isTablet
                    && SystemUiProxy.INSTANCE.get(mLauncher).isActive()
                    && !mExternalTransitionStatusProvider.hasRun()) {
                // Preemptively start the unfold animation to make sure that we have drawn
                // the first frame of the animation before the screen gets unblocked
                preemptivelyStartAnimationOnNextFrame();
            }

            if (!dp.isTablet) {
                mExternalTransitionStatusProvider.onFolded();
            }
        }

        mIsTablet = dp.isTablet;
@@ -222,4 +241,48 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL
            HOTSEAT_SCALE_PROPERTY.setValue(mLauncher.getHotseat(), value);
        }
    }

    /**
     * Class to track the current status of the external transition provider (the events are coming
     * from the SystemUI side through IPC), it allows to check if the transition has already
     * finished or currently running on the SystemUI side since last unfold.
     */
    private static class TransitionStatusProvider implements TransitionProgressListener {

        private boolean mHasRun = false;

        @Override
        public void onTransitionStarted() {
            markAsRun();
        }

        @Override
        public void onTransitionProgress(float progress) {
            markAsRun();
        }

        @Override
        public void onTransitionFinished() {
            markAsRun();
        }

        /**
         * Called when the device is folded, so we can reset the status of the animation
         */
        public void onFolded() {
            mHasRun = false;
        }

        /**
         * Returns true if there was an animation already (or it is currently running) after
         * unfolding the device
         */
        public boolean hasRun() {
            return mHasRun;
        }

        private void markAsRun() {
            mHasRun = true;
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -302,7 +302,7 @@ public final class FeatureFlags {
            "Enable widget transition animation when resizing the widgets");

    public static final BooleanFlag PREEMPTIVE_UNFOLD_ANIMATION_START = getDebugFlag(270397209,
            "PREEMPTIVE_UNFOLD_ANIMATION_START", DISABLED,
            "PREEMPTIVE_UNFOLD_ANIMATION_START", ENABLED,
            "Enables starting the unfold animation preemptively when unfolding, without"
                    + "waiting for SystemUI and then merging the SystemUI progress whenever we "
                    + "start receiving the events");
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.launcher3.util

import java.io.PrintWriter
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

/**
 * A utility class to record and log events. Events are stored in a fixed size array and old logs
 * are purged as new events come.
 */
class EventLogArray(private val name: String, size: Int) {

    companion object {
        private const val TYPE_ONE_OFF = 0
        private const val TYPE_FLOAT = 1
        private const val TYPE_INTEGER = 2
        private const val TYPE_BOOL_TRUE = 3
        private const val TYPE_BOOL_FALSE = 4
        private fun isEntrySame(entry: EventEntry?, type: Int, event: String): Boolean {
            return entry != null && entry.type == type && entry.event == event
        }
    }

    private val logs: Array<EventEntry?>
    private var nextIndex = 0

    init {
        logs = arrayOfNulls(size)
    }

    fun addLog(event: String) {
        addLog(TYPE_ONE_OFF, event, 0f)
    }

    fun addLog(event: String, extras: Int) {
        addLog(TYPE_INTEGER, event, extras.toFloat())
    }

    fun addLog(event: String, extras: Float) {
        addLog(TYPE_FLOAT, event, extras)
    }

    fun addLog(event: String, extras: Boolean) {
        addLog(if (extras) TYPE_BOOL_TRUE else TYPE_BOOL_FALSE, event, 0f)
    }

    private fun addLog(type: Int, event: String, extras: Float) {
        // Merge the logs if it's a duplicate
        val last = (nextIndex + logs.size - 1) % logs.size
        val secondLast = (nextIndex + logs.size - 2) % logs.size
        if (isEntrySame(logs[last], type, event) && isEntrySame(logs[secondLast], type, event)) {
            logs[last]!!.update(type, event, extras)
            logs[secondLast]!!.duplicateCount++
            return
        }
        if (logs[nextIndex] == null) {
            logs[nextIndex] = EventEntry()
        }
        logs[nextIndex]!!.update(type, event, extras)
        nextIndex = (nextIndex + 1) % logs.size
    }

    fun dump(prefix: String, writer: PrintWriter) {
        writer.println("$prefix$name event history:")
        val sdf = SimpleDateFormat("  HH:mm:ss.SSSZ  ", Locale.US)
        val date = Date()
        for (i in logs.indices) {
            val log = logs[(nextIndex + logs.size - i - 1) % logs.size] ?: continue
            date.time = log.time
            val msg = StringBuilder(prefix).append(sdf.format(date)).append(log.event)
            when (log.type) {
                TYPE_BOOL_FALSE -> msg.append(": false")
                TYPE_BOOL_TRUE -> msg.append(": true")
                TYPE_FLOAT -> msg.append(": ").append(log.extras)
                TYPE_INTEGER -> msg.append(": ").append(log.extras.toInt())
                else -> {}
            }
            if (log.duplicateCount > 0) {
                msg.append(" & ").append(log.duplicateCount).append(" similar events")
            }
            writer.println(msg)
        }
    }

    /** A single event entry. */
    private class EventEntry {
        var type = 0
        var event: String? = null
        var extras = 0f
        var time: Long = 0
        var duplicateCount = 0
        fun update(type: Int, event: String, extras: Float) {
            this.type = type
            this.event = event
            this.extras = extras
            time = System.currentTimeMillis()
            duplicateCount = 0
        }
    }
}