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

Commit d2d94f4c authored by William Xiao's avatar William Xiao
Browse files

Add bottom right chip to dream overlay to show glanceable hub

This is added temporarily behind a flag for UX testing purposes and is
not intended to be a proper, full implementation.

Chip can be moved to the bottom left, replacing the home controls
button, by changing the system setting
open_hub_chip_replace_home_controls to 1.

Bug: 339667383
Test: N/A
Flag: com.android.systemui.glanceable_hub_shortcut_button
Change-Id: I34ef11c5d764ca46aea074b14d19f2ac804e3941
parent 6ed86daa
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -989,6 +989,13 @@ flag {
  }
}

flag {
  name: "glanceable_hub_shortcut_button"
  namespace: "systemui"
  description: "Shows a button over the dream and lock screen to open the glanceable hub"
  bug: "339667383"
}

flag {
  name: "glanceable_hub_gesture_handle"
  namespace: "systemui"
+27 −0
Original line number Diff line number Diff line
<!--
  ~ Copyright (C) 2024 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.
  -->

<!-- go/gm2-icons, from gs_widgets_vd_theme_24.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:tint="?attr/colorControlNormal"
    android:viewportHeight="960"
    android:viewportWidth="960">
    <path
        android:fillColor="@android:color/black"
        android:pathData="M666,520L440,294L666,68L892,294L666,520ZM120,440L120,120L440,120L440,440L120,440ZM520,840L520,520L840,520L840,840L520,840ZM120,840L120,520L440,520L440,840L120,840ZM200,360L360,360L360,200L200,200L200,360ZM667,408L780,295L667,182L554,295L667,408ZM600,760L760,760L760,600L600,600L600,760ZM200,760L360,760L360,600L200,600L200,760ZM360,360L360,360L360,360L360,360L360,360ZM554,295L554,295L554,295L554,295L554,295ZM360,600L360,600L360,600L360,600L360,600ZM600,600L600,600L600,600L600,600L600,600Z" />
</vector>
 No newline at end of file
+26 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2024 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.
-->
<com.android.systemui.animation.view.LaunchableImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="@dimen/dream_overlay_bottom_affordance_height"
    android:layout_width="@dimen/dream_overlay_bottom_affordance_width"
    android:layout_gravity="bottom|start"
    android:padding="@dimen/dream_overlay_bottom_affordance_padding"
    android:scaleType="fitCenter"
    android:tint="?android:attr/textColorPrimary"
    android:src="@drawable/ic_widgets"
    android:contentDescription="@string/accessibility_action_open_communal_hub" />
+9 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.complication;

import static com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent.DreamHomeControlsModule.DREAM_HOME_CONTROLS_CHIP_VIEW;
import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS;
import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS;
import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK;
import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE;
@@ -35,6 +36,7 @@ import androidx.annotation.Nullable;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.Utils;
import com.android.systemui.CoreStartable;
import com.android.systemui.Flags;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent;
import com.android.systemui.controls.ControlsServiceInfo;
@@ -89,6 +91,7 @@ public class DreamHomeControlsComplication implements Complication {
        private final DreamHomeControlsComplication mComplication;
        private final DreamOverlayStateController mDreamOverlayStateController;
        private final ControlsComponent mControlsComponent;
        private final boolean mReplacedByOpenHub;

        private boolean mOverlayActive = false;

@@ -116,11 +119,13 @@ public class DreamHomeControlsComplication implements Complication {
        public Registrant(DreamHomeControlsComplication complication,
                DreamOverlayStateController dreamOverlayStateController,
                ControlsComponent controlsComponent,
                @SystemUser Monitor monitor) {
                @SystemUser Monitor monitor,
                @Named(OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS) boolean replacedByOpenHub) {
            super(monitor);
            mComplication = complication;
            mControlsComponent = controlsComponent;
            mDreamOverlayStateController = dreamOverlayStateController;
            mReplacedByOpenHub = replacedByOpenHub;
        }

        @Override
@@ -132,7 +137,9 @@ public class DreamHomeControlsComplication implements Complication {

        private void updateHomeControlsComplication() {
            mControlsComponent.getControlsListingController().ifPresent(c -> {
                if (isHomeControlsAvailable(c.getCurrentServices())) {
                final boolean replacedWithOpenHub =
                        Flags.glanceableHubShortcutButton() && mReplacedByOpenHub;
                if (isHomeControlsAvailable(c.getCurrentServices()) && !replacedWithOpenHub) {
                    mDreamOverlayStateController.addComplication(mComplication);
                } else {
                    mDreamOverlayStateController.removeComplication(mComplication);
+212 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.complication;

import static com.android.systemui.complication.dagger.OpenHubComplicationComponent.OpenHubModule.OPEN_HUB_CHIP_VIEW;
import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.OPEN_HUB_CHIP_LAYOUT_PARAMS;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import com.android.settingslib.Utils;
import com.android.systemui.CoreStartable;
import com.android.systemui.Flags;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.communal.shared.model.CommunalScenes;
import com.android.systemui.complication.dagger.OpenHubComplicationComponent;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.shared.condition.Monitor;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.condition.ConditionalCoreStartable;

import javax.inject.Inject;
import javax.inject.Named;

/**
 * A dream complication that shows a chip to open the glanceable hub.
 */
// TODO(b/339667383): delete or properly implement this once a product decision is made
public class OpenHubComplication implements Complication {
    private final Resources mResources;
    private final OpenHubComplicationComponent.Factory mComponentFactory;

    @Inject
    public OpenHubComplication(
            @Main Resources resources,
            OpenHubComplicationComponent.Factory componentFactory) {
        mResources = resources;
        mComponentFactory = componentFactory;
    }

    @Override
    public ViewHolder createView(ComplicationViewModel model) {
        return mComponentFactory.create(mResources).getViewHolder();
    }

    @Override
    public int getRequiredTypeAvailability() {
        // TODO(b/339667383): create a new complication type if we decide to productionize this
        return COMPLICATION_TYPE_HOME_CONTROLS;
    }

    /**
     * {@link CoreStartable} for registering the complication with SystemUI on startup.
     */
    public static class Registrant extends ConditionalCoreStartable {
        private final OpenHubComplication mComplication;
        private final DreamOverlayStateController mDreamOverlayStateController;

        private boolean mOverlayActive = false;

        private final DreamOverlayStateController.Callback mOverlayStateCallback =
                new DreamOverlayStateController.Callback() {
                    @Override
                    public void onStateChanged() {
                        if (mOverlayActive == mDreamOverlayStateController.isOverlayActive()) {
                            return;
                        }

                        mOverlayActive = !mOverlayActive;

                        if (mOverlayActive) {
                            updateOpenHubComplication();
                        }
                    }
                };

        @Inject
        public Registrant(OpenHubComplication complication,
                DreamOverlayStateController dreamOverlayStateController,
                @SystemUser Monitor monitor) {
            super(monitor);
            mComplication = complication;
            mDreamOverlayStateController = dreamOverlayStateController;
        }

        @Override
        public void onStart() {
            mDreamOverlayStateController.addCallback(mOverlayStateCallback);
        }

        private void updateOpenHubComplication() {
            // TODO(b/339667383): don't show the complication if glanceable hub is disabled
            if (Flags.glanceableHubShortcutButton()) {
                mDreamOverlayStateController.addComplication(mComplication);
            } else {
                mDreamOverlayStateController.removeComplication(mComplication);
            }
        }
    }

    /**
     * Contains values/logic associated with the dream complication view.
     */
    public static class OpenHubChipViewHolder implements ViewHolder {
        private final ImageView mView;
        private final ComplicationLayoutParams mLayoutParams;
        private final OpenHubChipViewController mViewController;

        @Inject
        OpenHubChipViewHolder(
                OpenHubChipViewController dreamOpenHubChipViewController,
                @Named(OPEN_HUB_CHIP_VIEW) ImageView view,
                @Named(OPEN_HUB_CHIP_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams
        ) {
            mView = view;
            mLayoutParams = layoutParams;
            mViewController = dreamOpenHubChipViewController;
            mViewController.init();
        }

        @Override
        public ImageView getView() {
            return mView;
        }

        @Override
        public ComplicationLayoutParams getLayoutParams() {
            return mLayoutParams;
        }
    }

    /**
     * Controls behavior of the dream complication.
     */
    static class OpenHubChipViewController extends ViewController<ImageView> {
        private static final String TAG = "OpenHubCtrl";
        private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

        private final Context mContext;
        private final ConfigurationController mConfigurationController;

        private final ConfigurationController.ConfigurationListener mConfigurationListener =
                new ConfigurationController.ConfigurationListener() {
                    @Override
                    public void onUiModeChanged() {
                        reloadResources();
                    }
                };
        private final CommunalInteractor mCommunalInteractor;

        @Inject
        OpenHubChipViewController(
                @Named(OPEN_HUB_CHIP_VIEW) ImageView view,
                Context context,
                ConfigurationController configurationController,
                CommunalInteractor communalInteractor) {
            super(view);

            mContext = context;
            mConfigurationController = configurationController;
            mCommunalInteractor = communalInteractor;
        }

        @Override
        protected void onViewAttached() {
            reloadResources();
            mView.setOnClickListener(this::onClickOpenHub);
            mConfigurationController.addCallback(mConfigurationListener);
        }

        @Override
        protected void onViewDetached() {
            mConfigurationController.removeCallback(mConfigurationListener);
        }

        private void reloadResources() {
            mView.setImageTintList(Utils.getColorAttr(mContext, android.R.attr.textColorPrimary));
            final Drawable background = mView.getBackground();
            if (background != null) {
                background.setTintList(
                        Utils.getColorAttr(mContext, com.android.internal.R.attr.colorSurface));
            }
        }

        private void onClickOpenHub(View v) {
            if (DEBUG) Log.d(TAG, "open hub complication tapped");

            mCommunalInteractor.changeScene(CommunalScenes.Communal, null);
        }
    }
}
Loading