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

Commit 6fb22d4b authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Implementation of the FooterActions following the MAD (1/3)

This CL provides most of the implementation of the QS FooterActions
following the modern Android architecture. In particular, this CL
includes:
 - repositories in the data layer.
 - an interactor in the domain layer.
 - a view model in the ui layer.

The ViewBinder is added in ag/19674347, given that it comes together
with changes to the existing XML files.

Note that after this CL, the new implementation will still not be used
as it won't be wired yet. This is done in ag/19674347.

The highest value of the tests is in FooterActionsViewModelTest, which
focuses on testing the *state* (view model) of the footer actions using
the *real implementation* of the repositories, interactor and viewModel
all together. To do so, I implemented a FooterActionsUtils class that
allows to *easily* create real implementations of those repositories,
interactor and view model, without requiring the caller to provide any
parameter. I believe that this is even better than introducing new
fakes, and it should hopefully lead us towards using more and more of
the real implementations in our tests, and less and less of fakes/mocks,
making the tests much more useful. Of course, I still had to use fake &
mocks for the classes I'm calling to and for which instantiating the
actual object is too painful. As you can see, there are no test files
for the repositories: given that we already use the real implementations
in the ViewModel tests, they are defacto already tested.

I still added some tests on *interactions* (not *state*) in
FooterActionsInteractorTest. Even though I believe those tests don't
provide much value (they are merely a copy/paste of the implementation),
I preferred keeping the same coverage as the current tests (some of
which are going to be removed in ag/19674347).

Note that the business logic contained in this CL was mostly copy/pasted
from the current implementation, as I wanted to make sure that this is
going to be a pure refactoring that does not change the logic of this
feature. Still, I left some TODOs in the code for potential
improvements.

Bug: 242040009
Test: atest FooterActionsViewModelTest
Test: atest FooterActionsInteractorTest
Change-Id: Ia0bdf9824e098ad6604709f5db87576437b0a904
parent c9a5847b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -230,6 +230,7 @@ android_library {
    libs: [
        "android.test.runner",
        "android.test.base",
        "android.test.mock",
    ],
    kotlincflags: ["-Xjvm-default=enable"],
    aaptflags: [
+1 −2
Original line number Diff line number Diff line
@@ -311,8 +311,7 @@ class ActivityLaunchAnimator(
            @JvmStatic
            fun fromView(view: View, cujType: Int? = null): Controller? {
                if (view.parent !is ViewGroup) {
                    // TODO(b/192194319): Throw instead of just logging.
                    Log.wtf(
                    Log.e(
                        TAG,
                        "Skipping animation as view $view is not attached to a ViewGroup",
                        Exception()
+52 −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.systemui.animation

import android.view.View

/** A piece of UI that can be expanded into a Dialog or an Activity. */
interface Expandable {
    /**
     * Create an [ActivityLaunchAnimator.Controller] that can be used to expand this [Expandable]
     * into an Activity, or return `null` if this [Expandable] should not be animated (e.g. if it is
     * currently not attached or visible).
     *
     * @param cujType the CUJ type from the [com.android.internal.jank.InteractionJankMonitor]
     * associated to the launch that will use this controller.
     */
    fun activityLaunchController(cujType: Int? = null): ActivityLaunchAnimator.Controller?

    // TODO(b/230830644): Introduce DialogLaunchAnimator and a function to expose it here.

    companion object {
        /**
         * Create an [Expandable] that will animate [view] when expanded.
         *
         * Note: The background of [view] should be a (rounded) rectangle so that it can be properly
         * animated.
         */
        fun fromView(view: View): Expandable {
            return object : Expandable {
                override fun activityLaunchController(
                    cujType: Int?,
                ): ActivityLaunchAnimator.Controller? {
                    return ActivityLaunchAnimator.Controller.fromView(view, cujType)
                }
            }
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -54,6 +54,11 @@ android_library {
        "testables",
        "truth-prebuilt",
        "androidx.test.uiautomator",
        "kotlinx_coroutines_test",
    ],

    libs: [
        "android.test.mock",
    ],

    kotlincflags: ["-Xjvm-default=all"],
+33 −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.systemui.common.shared.model

import android.annotation.StringRes

/**
 * Models a content description, that can either be already [loaded][ContentDescription.Loaded] or
 * be a [reference][ContentDescription.Resource] to a resource.
 */
sealed class ContentDescription {
    data class Loaded(
        val description: String?,
    ) : ContentDescription()

    data class Resource(
        @StringRes val res: Int,
    ) : ContentDescription()
}
Loading