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

Commit 55275d88 authored by Bryce Lee's avatar Bryce Lee Committed by Android (Google) Code Review
Browse files

Merge "Complication Entity & Presentation Refactor."

parents d95703d1 8c39ada0
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/dream_overlay_complications_layer"
    android:padding="20dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextClock
+0 −2
Original line number Diff line number Diff line
@@ -28,8 +28,6 @@
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

    <include layout="@layout/dream_overlay_complications_layer" />

    <com.android.systemui.dreams.DreamOverlayStatusBarView
        android:id="@+id/dream_overlay_status_bar"
        android:layout_width="match_parent"
+0 −85
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.dreams;

import android.annotation.IntDef;
import android.content.Context;

import com.android.settingslib.dream.DreamBackend;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * {@link ComplicationProvider} is an interface for defining entities that can supply complications
 * to show over a dream. Presentation components such as the {@link DreamOverlayService} supply
 * implementations with the necessary context for constructing such overlays.
 */
public interface ComplicationProvider {
    /**
     * The type of dream complications which can be provided by a {@link ComplicationProvider}.
     */
    @IntDef(prefix = {"COMPLICATION_TYPE_"}, flag = true, value = {
            COMPLICATION_TYPE_NONE,
            COMPLICATION_TYPE_TIME,
            COMPLICATION_TYPE_DATE,
            COMPLICATION_TYPE_WEATHER,
            COMPLICATION_TYPE_AIR_QUALITY,
            COMPLICATION_TYPE_CAST_INFO
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface ComplicationType {}

    int COMPLICATION_TYPE_NONE = 0;
    int COMPLICATION_TYPE_TIME = 1;
    int COMPLICATION_TYPE_DATE = 1 << 1;
    int COMPLICATION_TYPE_WEATHER = 1 << 2;
    int COMPLICATION_TYPE_AIR_QUALITY = 1 << 3;
    int COMPLICATION_TYPE_CAST_INFO = 1 << 4;

    /**
     * Called when the {@link ComplicationHost} requests the associated complication be produced.
     *
     * @param context The {@link Context} used to construct the view.
     * @param creationCallback The callback to inform the complication has been created.
     * @param interactionCallback The callback to inform the complication has been interacted with.
     */
    void onCreateComplication(Context context, ComplicationHost.CreationCallback creationCallback,
            ComplicationHost.InteractionCallback interactionCallback);

    /**
     * Converts a {@link com.android.settingslib.dream.DreamBackend.ComplicationType} to
     * {@link ComplicationType}.
     */
    @ComplicationType
    default int convertComplicationType(@DreamBackend.ComplicationType int type) {
        switch (type) {
            case DreamBackend.COMPLICATION_TYPE_TIME:
                return COMPLICATION_TYPE_TIME;
            case DreamBackend.COMPLICATION_TYPE_DATE:
                return COMPLICATION_TYPE_DATE;
            case DreamBackend.COMPLICATION_TYPE_WEATHER:
                return COMPLICATION_TYPE_WEATHER;
            case DreamBackend.COMPLICATION_TYPE_AIR_QUALITY:
                return COMPLICATION_TYPE_AIR_QUALITY;
            case DreamBackend.COMPLICATION_TYPE_CAST_INFO:
                return COMPLICATION_TYPE_CAST_INFO;
            default:
                return COMPLICATION_TYPE_NONE;
        }
    }
}
+20 −10
Original line number Diff line number Diff line
@@ -25,11 +25,11 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;

import androidx.constraintlayout.widget.ConstraintLayout;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.complication.dagger.ComplicationHostViewComponent;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
import com.android.systemui.util.ViewController;
@@ -47,6 +47,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
    private final int mDreamOverlayNotificationsDragAreaHeight;
    private final DreamOverlayStatusBarViewController mStatusBarViewController;

    private final ComplicationHostViewController mComplicationHostViewController;

    // The dream overlay's content view, which is located below the status bar (in z-order) and is
    // the space into which widgets are placed.
    private final ViewGroup mDreamOverlayContentView;
@@ -74,6 +76,13 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
                    final int childCount = mDreamOverlayContentView.getChildCount();
                    for (int i = 0; i < childCount; i++) {
                        View child = mDreamOverlayContentView.getChildAt(i);

                        if (mComplicationHostViewController.getView() == child) {
                            region.op(mComplicationHostViewController.getTouchRegions(),
                                    Region.Op.UNION);
                            continue;
                        }

                        if (child.getGlobalVisibleRect(rect)) {
                            region.op(rect, Region.Op.UNION);
                        }
@@ -93,6 +102,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
    @Inject
    public DreamOverlayContainerViewController(
            DreamOverlayContainerView containerView,
            ComplicationHostViewComponent.Factory complicationHostViewFactory,
            @Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
            DreamOverlayStatusBarViewController statusBarViewController,
            @Main Handler handler,
@@ -106,6 +116,13 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
                mView.getResources().getDimensionPixelSize(
                        R.dimen.dream_overlay_notifications_drag_area_height);

        mComplicationHostViewController = complicationHostViewFactory.create().getController();
        final View view = mComplicationHostViewController.getView();

        mDreamOverlayContentView.addView(view,
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT));

        mHandler = handler;
        mMaxBurnInOffset = maxBurnInOffset;
        mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval;
@@ -114,6 +131,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
    @Override
    protected void onInit() {
        mStatusBarViewController.init();
        mComplicationHostViewController.init();
    }

    @Override
@@ -130,18 +148,10 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
                .removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
    }

    void addOverlay(View overlayView, ConstraintLayout.LayoutParams layoutParams) {
        mDreamOverlayContentView.addView(overlayView, layoutParams);
    }

    View getContainerView() {
        return mView;
    }

    void removeAllOverlays() {
        mDreamOverlayContentView.removeAllViews();
    }

    @VisibleForTesting
    int getDreamOverlayNotificationsDragAreaHeight() {
        return mDreamOverlayNotificationsDragAreaHeight;
+29 −39
Original line number Diff line number Diff line
@@ -24,10 +24,13 @@ import android.view.WindowInsets;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.ViewModelStore;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.PhoneWindow;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;

import java.util.concurrent.Executor;
@@ -47,8 +50,6 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
    private final Context mContext;
    // The Executor ensures actions and ui updates happen on the same thread.
    private final Executor mExecutor;
    // The state controller informs the service of updates to the complications present.
    private final DreamOverlayStateController mStateController;
    // A controller for the dream overlay container view (which contains both the status bar and the
    // content area).
    private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
@@ -56,47 +57,51 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
    // A reference to the {@link Window} used to hold the dream overlay.
    private Window mWindow;

    private final DreamOverlayStateController.Callback mOverlayStateCallback =
            new DreamOverlayStateController.Callback() {
    private final Complication.Host mHost = new Complication.Host() {
        @Override
                public void onComplicationsChanged() {
                    mExecutor.execute(() -> reloadComplicationsLocked());
        public void requestExitDream() {
            mExecutor.execute(DreamOverlayService.this::requestExit);
        }
    };

    private final LifecycleRegistry mLifecycleRegistry;

    private ViewModelStore mViewModelStore = new ViewModelStore();

    @Inject
    public DreamOverlayService(
            Context context,
            @Main Executor executor,
            DreamOverlayStateController overlayStateController,
            DreamOverlayComponent.Factory dreamOverlayComponentFactory) {
        mContext = context;
        mExecutor = executor;
        mStateController = overlayStateController;
        mDreamOverlayContainerViewController =
                dreamOverlayComponentFactory.create().getDreamOverlayContainerViewController();

        mStateController.addCallback(mOverlayStateCallback);
        final DreamOverlayComponent component =
                dreamOverlayComponentFactory.create(mViewModelStore, mHost);
        mDreamOverlayContainerViewController = component.getDreamOverlayContainerViewController();
        setCurrentState(Lifecycle.State.CREATED);
        mLifecycleRegistry = component.getLifecycleRegistry();
    }

    private void setCurrentState(Lifecycle.State state) {
        mExecutor.execute(() -> mLifecycleRegistry.setCurrentState(state));
    }

    @Override
    public void onDestroy() {
        setCurrentState(Lifecycle.State.DESTROYED);
        final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
        windowManager.removeView(mWindow.getDecorView());
        mStateController.removeCallback(mOverlayStateCallback);
        super.onDestroy();
    }

    @Override
    public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
        mExecutor.execute(() -> addOverlayWindowLocked(layoutParams));
    }

    private void reloadComplicationsLocked() {
        mDreamOverlayContainerViewController.removeAllOverlays();
        for (ComplicationProvider overlayProvider : mStateController.getComplications()) {
            addComplication(overlayProvider);
        }
        setCurrentState(Lifecycle.State.STARTED);
        mExecutor.execute(() -> {
            addOverlayWindowLocked(layoutParams);
            setCurrentState(Lifecycle.State.RESUMED);
        });
    }

    /**
@@ -129,20 +134,5 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ

        final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
        windowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
        mExecutor.execute(this::reloadComplicationsLocked);
    }

    @VisibleForTesting
    protected void addComplication(ComplicationProvider provider) {
        provider.onCreateComplication(mContext,
                (view, layoutParams) -> {
                    // Always move UI related work to the main thread.
                    mExecutor.execute(() -> mDreamOverlayContainerViewController
                            .addOverlay(view, layoutParams));
                },
                () -> {
                    // The Callback is set on the main thread.
                    mExecutor.execute(this::requestExit);
                });
    }
}
Loading