1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.accessibility.floatingmenu;
18 
19 import static android.util.TypedValue.COMPLEX_UNIT_PX;
20 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
21 
22 import android.annotation.IntDef;
23 import android.content.ComponentCallbacks;
24 import android.content.Context;
25 import android.content.res.ColorStateList;
26 import android.content.res.Configuration;
27 import android.content.res.Resources;
28 import android.graphics.Rect;
29 import android.view.Gravity;
30 import android.view.View;
31 import android.view.ViewTreeObserver;
32 import android.widget.Button;
33 import android.widget.FrameLayout;
34 import android.widget.LinearLayout;
35 import android.widget.TextView;
36 
37 import androidx.annotation.NonNull;
38 
39 import com.android.settingslib.Utils;
40 import com.android.systemui.R;
41 
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 
45 /**
46  * The message view with the action prompt to whether to undo operation for users when removing
47  * the {@link MenuView}.
48  */
49 class MenuMessageView extends LinearLayout implements
50         ViewTreeObserver.OnComputeInternalInsetsListener, ComponentCallbacks {
51     private final TextView mTextView;
52     private final Button mUndoButton;
53 
54     @IntDef({
55             Index.TEXT_VIEW,
56             Index.UNDO_BUTTON
57     })
58     @Retention(RetentionPolicy.SOURCE)
59     @interface Index {
60         int TEXT_VIEW = 0;
61         int UNDO_BUTTON = 1;
62     }
63 
MenuMessageView(Context context)64     MenuMessageView(Context context) {
65         super(context);
66 
67         setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
68         setVisibility(GONE);
69 
70         mTextView = new TextView(context);
71         mUndoButton = new Button(context);
72 
73         addView(mTextView, Index.TEXT_VIEW,
74                 new LayoutParams(/* width= */ 0, WRAP_CONTENT, /* weight= */ 1));
75         addView(mUndoButton, Index.UNDO_BUTTON, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
76     }
77 
78     @Override
onConfigurationChanged(@onNull Configuration newConfig)79     public void onConfigurationChanged(@NonNull Configuration newConfig) {
80         updateResources();
81     }
82 
83     @Override
onLowMemory()84     public void onLowMemory() {
85         // Do nothing.
86     }
87 
88     @Override
onAttachedToWindow()89     protected void onAttachedToWindow() {
90         super.onAttachedToWindow();
91 
92         final FrameLayout.LayoutParams containerParams = new FrameLayout.LayoutParams(WRAP_CONTENT,
93                 WRAP_CONTENT);
94         containerParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
95         setLayoutParams(containerParams);
96         setGravity(Gravity.CENTER_VERTICAL);
97 
98         mUndoButton.setBackground(null);
99 
100         updateResources();
101 
102         getContext().registerComponentCallbacks(this);
103         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
104     }
105 
106     @Override
onDetachedFromWindow()107     protected void onDetachedFromWindow() {
108         super.onDetachedFromWindow();
109 
110         getContext().unregisterComponentCallbacks(this);
111         getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
112     }
113 
114     @Override
onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo)115     public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
116         inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
117 
118         if (getVisibility() == VISIBLE) {
119             final int x = (int) getX();
120             final int y = (int) getY();
121             inoutInfo.touchableRegion.union(new Rect(x, y, x + getWidth(), y + getHeight()));
122         }
123     }
124 
125     /**
126      * Registers a listener to be invoked when this undo action button is clicked. It should be
127      * called after {@link View#onAttachedToWindow()}.
128      *
129      * @param listener The listener that will run
130      */
setUndoListener(OnClickListener listener)131     void setUndoListener(OnClickListener listener) {
132         mUndoButton.setOnClickListener(listener);
133     }
134 
updateResources()135     private void updateResources() {
136         final Resources res = getResources();
137 
138         final int containerPadding =
139                 res.getDimensionPixelSize(
140                         R.dimen.accessibility_floating_menu_message_container_horizontal_padding);
141         final int margin = res.getDimensionPixelSize(
142                 R.dimen.accessibility_floating_menu_message_margin);
143         final FrameLayout.LayoutParams containerParams =
144                 (FrameLayout.LayoutParams) getLayoutParams();
145         containerParams.setMargins(margin, margin, margin, margin);
146         setLayoutParams(containerParams);
147         setBackground(res.getDrawable(R.drawable.accessibility_floating_message_background));
148         setPadding(containerPadding, /* top= */ 0, containerPadding, /* bottom= */ 0);
149         setMinimumWidth(
150                 res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_message_min_width));
151         setMinimumHeight(
152                 res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_message_min_height));
153         setElevation(
154                 res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_message_elevation));
155 
156         final int textPadding =
157                 res.getDimensionPixelSize(
158                         R.dimen.accessibility_floating_menu_message_text_vertical_padding);
159         final int textColor = res.getColor(R.color.accessibility_floating_menu_message_text);
160         final int textSize = res.getDimensionPixelSize(
161                 R.dimen.accessibility_floating_menu_message_text_size);
162         mTextView.setPadding(/* left= */ 0, textPadding, /* right= */ 0, textPadding);
163         mTextView.setTextSize(COMPLEX_UNIT_PX, textSize);
164         mTextView.setTextColor(textColor);
165 
166         final ColorStateList colorAccent = Utils.getColorAccent(getContext());
167         mUndoButton.setText(res.getString(R.string.accessibility_floating_button_undo));
168         mUndoButton.setTextSize(COMPLEX_UNIT_PX, textSize);
169         mUndoButton.setTextColor(colorAccent);
170     }
171 }
172