blob: 347d3009c3ec8855d155b8176ddc19da8a63af47 [file] [log] [blame]
Petr Cermak10011fa2018-02-05 19:00:54 +00001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.statusbar.policy;
18
Milo Sredkov41dc4ba2018-12-27 12:03:45 +000019import android.app.RemoteInput;
Petr Cermak10011fa2018-02-05 19:00:54 +000020import android.content.Context;
21import android.content.res.Resources;
Petr Cermak10011fa2018-02-05 19:00:54 +000022import android.os.Handler;
Gustav Sennton8fa7e952019-01-29 19:37:00 +000023import android.provider.DeviceConfig;
24import android.text.TextUtils;
Petr Cermak10011fa2018-02-05 19:00:54 +000025import android.util.KeyValueListParser;
26import android.util.Log;
27
Gustav Sennton8fa7e952019-01-29 19:37:00 +000028import com.android.internal.annotations.VisibleForTesting;
29import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
Petr Cermak10011fa2018-02-05 19:00:54 +000030import com.android.systemui.R;
Dave Mankofff4736812019-10-18 17:25:50 -040031import com.android.systemui.dagger.qualifiers.MainHandler;
Petr Cermak10011fa2018-02-05 19:00:54 +000032
Jason Monk27d01a622018-12-10 15:57:09 -050033import javax.inject.Inject;
Jason Monk27d01a622018-12-10 15:57:09 -050034import javax.inject.Singleton;
35
36@Singleton
Gustav Sennton8fa7e952019-01-29 19:37:00 +000037public final class SmartReplyConstants {
Petr Cermak10011fa2018-02-05 19:00:54 +000038
39 private static final String TAG = "SmartReplyConstants";
40
Petr Cermak10011fa2018-02-05 19:00:54 +000041 private final boolean mDefaultEnabled;
Richard Ledley28944cb2018-02-26 10:36:00 +000042 private final boolean mDefaultRequiresP;
Petr Cermak10011fa2018-02-05 19:00:54 +000043 private final int mDefaultMaxSqueezeRemeasureAttempts;
Milo Sredkov41dc4ba2018-12-27 12:03:45 +000044 private final boolean mDefaultEditChoicesBeforeSending;
Gustav Sennton3f3eaff2019-01-08 09:39:51 +000045 private final boolean mDefaultShowInHeadsUp;
Gustav Senntona31f6ae2019-01-08 11:20:49 +000046 private final int mDefaultMinNumSystemGeneratedReplies;
Gustav Sennton4bf5ff52019-01-16 14:27:25 +000047 private final int mDefaultMaxNumActions;
Gustav Sennton8a52dc32019-04-15 12:48:23 +010048 private final int mDefaultOnClickInitDelay;
Petr Cermak10011fa2018-02-05 19:00:54 +000049
Gustav Senntoneb93c402019-02-25 18:44:01 +000050 // These fields are updated on the UI thread but can be accessed on both the UI thread and
51 // background threads. We use the volatile keyword here instead of synchronization blocks since
52 // we only care about variable updates here being visible to other threads (and not for example
53 // whether the variables we are reading were updated in the same go).
54 private volatile boolean mEnabled;
55 private volatile boolean mRequiresTargetingP;
56 private volatile int mMaxSqueezeRemeasureAttempts;
57 private volatile boolean mEditChoicesBeforeSending;
58 private volatile boolean mShowInHeadsUp;
59 private volatile int mMinNumSystemGeneratedReplies;
60 private volatile int mMaxNumActions;
Gustav Sennton8a52dc32019-04-15 12:48:23 +010061 private volatile long mOnClickInitDelay;
Petr Cermak10011fa2018-02-05 19:00:54 +000062
Gustav Sennton8fa7e952019-01-29 19:37:00 +000063 private final Handler mHandler;
Petr Cermak10011fa2018-02-05 19:00:54 +000064 private final Context mContext;
65 private final KeyValueListParser mParser = new KeyValueListParser(',');
66
Jason Monk27d01a622018-12-10 15:57:09 -050067 @Inject
Dave Mankofff4736812019-10-18 17:25:50 -040068 public SmartReplyConstants(@MainHandler Handler handler, Context context) {
Gustav Sennton8fa7e952019-01-29 19:37:00 +000069 mHandler = handler;
Petr Cermak10011fa2018-02-05 19:00:54 +000070 mContext = context;
71 final Resources resources = mContext.getResources();
72 mDefaultEnabled = resources.getBoolean(
73 R.bool.config_smart_replies_in_notifications_enabled);
Richard Ledley28944cb2018-02-26 10:36:00 +000074 mDefaultRequiresP = resources.getBoolean(
75 R.bool.config_smart_replies_in_notifications_requires_targeting_p);
Petr Cermak10011fa2018-02-05 19:00:54 +000076 mDefaultMaxSqueezeRemeasureAttempts = resources.getInteger(
77 R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts);
Milo Sredkov41dc4ba2018-12-27 12:03:45 +000078 mDefaultEditChoicesBeforeSending = resources.getBoolean(
79 R.bool.config_smart_replies_in_notifications_edit_choices_before_sending);
Gustav Sennton3f3eaff2019-01-08 09:39:51 +000080 mDefaultShowInHeadsUp = resources.getBoolean(
81 R.bool.config_smart_replies_in_notifications_show_in_heads_up);
Gustav Senntona31f6ae2019-01-08 11:20:49 +000082 mDefaultMinNumSystemGeneratedReplies = resources.getInteger(
83 R.integer.config_smart_replies_in_notifications_min_num_system_generated_replies);
Gustav Sennton4bf5ff52019-01-16 14:27:25 +000084 mDefaultMaxNumActions = resources.getInteger(
85 R.integer.config_smart_replies_in_notifications_max_num_actions);
Gustav Sennton8a52dc32019-04-15 12:48:23 +010086 mDefaultOnClickInitDelay = resources.getInteger(
87 R.integer.config_smart_replies_in_notifications_onclick_init_delay);
Petr Cermak10011fa2018-02-05 19:00:54 +000088
Gustav Sennton8fa7e952019-01-29 19:37:00 +000089 registerDeviceConfigListener();
Petr Cermak10011fa2018-02-05 19:00:54 +000090 updateConstants();
91 }
92
Gustav Sennton8fa7e952019-01-29 19:37:00 +000093 private void registerDeviceConfigListener() {
Matt Pape15769e22019-04-19 12:31:24 -070094 DeviceConfig.addOnPropertiesChangedListener(
Gustav Sennton8fa7e952019-01-29 19:37:00 +000095 DeviceConfig.NAMESPACE_SYSTEMUI,
96 this::postToHandler,
Matt Pape15769e22019-04-19 12:31:24 -070097 (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace()));
Gustav Sennton8fa7e952019-01-29 19:37:00 +000098 }
99
100 private void postToHandler(Runnable r) {
101 this.mHandler.post(r);
102 }
103
104 @VisibleForTesting
Matt Pape15769e22019-04-19 12:31:24 -0700105 void onDeviceConfigPropertiesChanged(String namespace) {
Gustav Sennton8fa7e952019-01-29 19:37:00 +0000106 if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
107 Log.e(TAG, "Received update from DeviceConfig for unrelated namespace: "
Matt Pape15769e22019-04-19 12:31:24 -0700108 + namespace);
Gustav Sennton8fa7e952019-01-29 19:37:00 +0000109 return;
110 }
111
Petr Cermak10011fa2018-02-05 19:00:54 +0000112 updateConstants();
113 }
114
115 private void updateConstants() {
116 synchronized (SmartReplyConstants.this) {
Gustav Sennton8fa7e952019-01-29 19:37:00 +0000117 mEnabled = readDeviceConfigBooleanOrDefaultIfEmpty(
118 SystemUiDeviceConfigFlags.SSIN_ENABLED,
119 mDefaultEnabled);
120 mRequiresTargetingP = readDeviceConfigBooleanOrDefaultIfEmpty(
121 SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P,
122 mDefaultRequiresP);
Stanislav Zholnin134115a2019-03-08 13:49:29 +0000123 mMaxSqueezeRemeasureAttempts = DeviceConfig.getInt(
124 DeviceConfig.NAMESPACE_SYSTEMUI,
Gustav Sennton8fa7e952019-01-29 19:37:00 +0000125 SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS,
126 mDefaultMaxSqueezeRemeasureAttempts);
127 mEditChoicesBeforeSending = readDeviceConfigBooleanOrDefaultIfEmpty(
128 SystemUiDeviceConfigFlags.SSIN_EDIT_CHOICES_BEFORE_SENDING,
129 mDefaultEditChoicesBeforeSending);
130 mShowInHeadsUp = readDeviceConfigBooleanOrDefaultIfEmpty(
131 SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP,
132 mDefaultShowInHeadsUp);
Stanislav Zholnin134115a2019-03-08 13:49:29 +0000133 mMinNumSystemGeneratedReplies = DeviceConfig.getInt(
134 DeviceConfig.NAMESPACE_SYSTEMUI,
Gustav Sennton8fa7e952019-01-29 19:37:00 +0000135 SystemUiDeviceConfigFlags.SSIN_MIN_NUM_SYSTEM_GENERATED_REPLIES,
136 mDefaultMinNumSystemGeneratedReplies);
Stanislav Zholnin134115a2019-03-08 13:49:29 +0000137 mMaxNumActions = DeviceConfig.getInt(
138 DeviceConfig.NAMESPACE_SYSTEMUI,
Gustav Sennton8fa7e952019-01-29 19:37:00 +0000139 SystemUiDeviceConfigFlags.SSIN_MAX_NUM_ACTIONS,
140 mDefaultMaxNumActions);
Gustav Sennton8a52dc32019-04-15 12:48:23 +0100141 mOnClickInitDelay = DeviceConfig.getInt(
142 DeviceConfig.NAMESPACE_SYSTEMUI,
143 SystemUiDeviceConfigFlags.SSIN_ONCLICK_INIT_DELAY,
144 mDefaultOnClickInitDelay);
Gustav Sennton8fa7e952019-01-29 19:37:00 +0000145 }
146 }
147
148 private static boolean readDeviceConfigBooleanOrDefaultIfEmpty(String propertyName,
149 boolean defaultValue) {
150 String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, propertyName);
151 if (TextUtils.isEmpty(value)) {
152 return defaultValue;
153 }
154 if ("true".equals(value)) {
155 return true;
156 }
157 if ("false".equals(value)) {
158 return false;
159 }
160 // For invalid configs we return the default value.
161 return defaultValue;
162 }
163
Petr Cermak10011fa2018-02-05 19:00:54 +0000164 /** Returns whether smart replies in notifications are enabled. */
165 public boolean isEnabled() {
166 return mEnabled;
167 }
168
169 /**
Richard Ledley28944cb2018-02-26 10:36:00 +0000170 * Returns whether smart replies in notifications should be disabled when the app targets a
171 * version of Android older than P.
172 */
173 public boolean requiresTargetingP() {
174 return mRequiresTargetingP;
175 }
176
177 /**
Petr Cermak10011fa2018-02-05 19:00:54 +0000178 * Returns the maximum number of times {@link SmartReplyView#onMeasure(int, int)} will try to
179 * find a better (narrower) line-break for a double-line smart reply button.
180 */
181 public int getMaxSqueezeRemeasureAttempts() {
182 return mMaxSqueezeRemeasureAttempts;
183 }
Milo Sredkov41dc4ba2018-12-27 12:03:45 +0000184
185 /**
186 * Returns whether by tapping on a choice should let the user edit the input before it
187 * is sent to the app.
188 *
189 * @param remoteInputEditChoicesBeforeSending The value from
190 * {@link RemoteInput#getEditChoicesBeforeSending()}
191 */
192 public boolean getEffectiveEditChoicesBeforeSending(
193 @RemoteInput.EditChoicesBeforeSending int remoteInputEditChoicesBeforeSending) {
194 switch (remoteInputEditChoicesBeforeSending) {
195 case RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED:
196 return false;
197 case RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED:
198 return true;
199 case RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO:
200 default:
201 return mEditChoicesBeforeSending;
202 }
203 }
Gustav Sennton3f3eaff2019-01-08 09:39:51 +0000204
205 /**
206 * Returns whether smart suggestions should be enabled in heads-up notifications.
207 */
208 public boolean getShowInHeadsUp() {
209 return mShowInHeadsUp;
210 }
Gustav Senntona31f6ae2019-01-08 11:20:49 +0000211
212 /**
213 * Returns the minimum number of system generated replies to show in a notification.
214 * If we cannot show at least this many system generated replies we should show none.
215 */
216 public int getMinNumSystemGeneratedReplies() {
217 return mMinNumSystemGeneratedReplies;
218 }
Gustav Sennton4bf5ff52019-01-16 14:27:25 +0000219
220 /**
221 * Returns the maximum number smart actions to show in a notification, or -1 if there shouldn't
222 * be a limit.
223 */
224 public int getMaxNumActions() {
225 return mMaxNumActions;
226 }
Gustav Sennton8a52dc32019-04-15 12:48:23 +0100227
228 /**
229 * Returns the amount of time (ms) before smart suggestions are clickable, since the suggestions
230 * were added.
231 */
232 public long getOnClickInitDelay() {
233 return mOnClickInitDelay;
234 }
Petr Cermak10011fa2018-02-05 19:00:54 +0000235}