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

Commit 23dcb503 authored by Ivan Tkachenko's avatar Ivan Tkachenko
Browse files

Bubble manage education

Bubble bar education is gonna be split between WMShell and Launcher modules, as the state of the education is stored in WMShell shared preferences, but the presentation logic of the stack education should reside in Launcher. The following CLs will focus on the bubble stack education. This CL implements bubble bar manage education logic.

List of changes:
* Added `BubbleEducationController` to encapsulate the bubble education state. Updated the current usages of the shared preferences to use the controller instead.
* Added `BubbleEducationViewConrtolelr` to manage bubble bar education presentation in WMShell.
* Added `BubblePopupView` and `BubblePopupDrawable` to common folder to be accessible by the Launcher. The drawable renders the rounded corners rect with the directional rounded arrow that has customisable position. Is used by the bubble bar manage education view and will be used by bubble bar stack education view in Launcher.
* Added dismiss opened education functionality and extended it to manage menu dismissal.

Bug: 275077944
Test: atest BubblesTest, manual
Flag: WM_BUBBLE_BAR
Change-Id: I579c24226050e3779892a24bc6cb867781a2fef0
parent b5acb73f
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ 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
  -->
<com.android.wm.shell.common.bubbles.BubblePopupView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_marginHorizontal="@dimen/bubble_popup_margin_horizontal"
    android:layout_marginTop="@dimen/bubble_popup_margin_top"
    android:elevation="@dimen/bubble_manage_menu_elevation"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <ImageView
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:tint="?android:attr/colorAccent"
        android:contentDescription="@null"
        android:src="@drawable/pip_ic_settings"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:maxWidth="@dimen/bubble_popup_content_max_width"
        android:maxLines="1"
        android:ellipsize="end"
        android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline"
        android:textColor="?android:attr/textColorPrimary"
        android:text="@string/bubble_bar_education_manage_title"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:maxWidth="@dimen/bubble_popup_content_max_width"
        android:textAppearance="@android:style/TextAppearance.DeviceDefault"
        android:textColor="?android:attr/textColorSecondary"
        android:textAlignment="center"
        android:text="@string/bubble_bar_education_manage_text"/>

</com.android.wm.shell.common.bubbles.BubblePopupView>
 No newline at end of file
+14 −0
Original line number Diff line number Diff line
@@ -226,6 +226,20 @@
    <dimen name="bubble_user_education_padding_end">58dp</dimen>
    <!-- Padding between the bubble and the user education text. -->
    <dimen name="bubble_user_education_stack_padding">16dp</dimen>
    <!-- Max width for the bubble popup view. -->
    <dimen name="bubble_popup_content_max_width">300dp</dimen>
    <!-- Horizontal margin for the bubble popup view. -->
    <dimen name="bubble_popup_margin_horizontal">32dp</dimen>
    <!-- Top margin for the bubble popup view. -->
    <dimen name="bubble_popup_margin_top">16dp</dimen>
    <!-- Width for the bubble popup view arrow. -->
    <dimen name="bubble_popup_arrow_width">12dp</dimen>
    <!-- Height for the bubble popup view arrow. -->
    <dimen name="bubble_popup_arrow_height">10dp</dimen>
    <!-- Corner radius for the bubble popup view arrow. -->
    <dimen name="bubble_popup_arrow_corner_radius">2dp</dimen>
    <!-- Padding for the bubble popup view contents. -->
    <dimen name="bubble_popup_padding">24dp</dimen>
    <!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
    <dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
    <!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
+5 −0
Original line number Diff line number Diff line
@@ -163,6 +163,11 @@
    <!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
    <string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>

    <!-- Title text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
    <string name="bubble_bar_education_manage_title">Control bubbles anytime</string>
    <!-- Descriptive text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
    <string name="bubble_bar_education_manage_text">Tap here to manage which apps and conversations can bubble</string>

    <!-- [CHAR LIMIT=100] Notification Importance title -->
    <string name="notification_bubble_title">Bubble</string>

+0 −1
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ import java.util.concurrent.Executor;
/**
 * Encapsulates the data and UI elements of a bubble.
 */
@VisibleForTesting
public class Bubble implements BubbleViewProvider {
    private static final String TAG = "Bubble";

+74 −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.wm.shell.bubbles

import android.content.Context
import android.util.Log
import androidx.core.content.edit
import com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION
import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES
import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME

/** Manages bubble education flags. Provides convenience methods to check the education state */
class BubbleEducationController(private val context: Context) {
    private val prefs = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)

    /** Whether the user has seen the stack education */
    @get:JvmName(name = "hasSeenStackEducation")
    var hasSeenStackEducation: Boolean
        get() = prefs.getBoolean(PREF_STACK_EDUCATION, false)
        set(value) = prefs.edit { putBoolean(PREF_STACK_EDUCATION, value) }

    /** Whether the user has seen the expanded view "manage" menu education */
    @get:JvmName(name = "hasSeenManageEducation")
    var hasSeenManageEducation: Boolean
        get() = prefs.getBoolean(PREF_MANAGED_EDUCATION, false)
        set(value) = prefs.edit { putBoolean(PREF_MANAGED_EDUCATION, value) }

    /** Whether education view should show for the collapsed stack. */
    fun shouldShowStackEducation(bubble: BubbleViewProvider?): Boolean {
        val shouldShow = bubble != null &&
                bubble.isConversationBubble && // show education for conversation bubbles only
                (!hasSeenStackEducation || BubbleDebugConfig.forceShowUserEducation(context))
        logDebug("Show stack edu: $shouldShow")
        return shouldShow
    }

    /** Whether the educational view should show for the expanded view "manage" menu. */
    fun shouldShowManageEducation(bubble: BubbleViewProvider?): Boolean {
        val shouldShow = bubble != null &&
                bubble.isConversationBubble && // show education for conversation bubbles only
                (!hasSeenManageEducation || BubbleDebugConfig.forceShowUserEducation(context))
        logDebug("Show manage edu: $shouldShow")
        return shouldShow
    }

    private fun logDebug(message: String) {
        if (DEBUG_USER_EDUCATION) {
            Log.d(TAG, message)
        }
    }

    companion object {
        private val TAG = if (TAG_WITH_CLASS_NAME) "BubbleEducationController" else TAG_BUBBLES
        const val PREF_STACK_EDUCATION: String = "HasSeenBubblesOnboarding"
        const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding"
    }
}

/** Convenience extension method to check if the bubble is a conversation bubble */
private val BubbleViewProvider.isConversationBubble: Boolean
    get() = if (this is Bubble) isConversation else false
Loading