1 /** 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 17 package android.ext.services.notification; 18 19 import android.content.ContentResolver; 20 import android.database.ContentObserver; 21 import android.net.Uri; 22 import android.os.Handler; 23 import android.provider.DeviceConfig; 24 import android.provider.Settings; 25 import android.util.Log; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; 29 30 /** 31 * Observes the settings for {@link Assistant}. 32 */ 33 final class AssistantSettings extends ContentObserver { 34 private static final String LOG_TAG = "AssistantSettings"; 35 public static Factory FACTORY = AssistantSettings::createAndRegister; 36 private static final boolean DEFAULT_GENERATE_REPLIES = true; 37 private static final boolean DEFAULT_GENERATE_ACTIONS = true; 38 private static final int DEFAULT_NEW_INTERRUPTION_MODEL_INT = 1; 39 private static final int DEFAULT_MAX_MESSAGES_TO_EXTRACT = 5; 40 @VisibleForTesting 41 static final int DEFAULT_MAX_SUGGESTIONS = 3; 42 43 private static final Uri STREAK_LIMIT_URI = 44 Settings.Global.getUriFor(Settings.Global.BLOCKING_HELPER_STREAK_LIMIT); 45 private static final Uri DISMISS_TO_VIEW_RATIO_LIMIT_URI = 46 Settings.Global.getUriFor( 47 Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT); 48 private static final Uri NOTIFICATION_NEW_INTERRUPTION_MODEL_URI = 49 Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL); 50 51 private final ContentResolver mResolver; 52 private final int mUserId; 53 54 private final Handler mHandler; 55 56 @VisibleForTesting 57 protected final Runnable mOnUpdateRunnable; 58 59 // Actual configuration settings. 60 float mDismissToViewRatioLimit; 61 int mStreakLimit; 62 boolean mGenerateReplies = DEFAULT_GENERATE_REPLIES; 63 boolean mGenerateActions = DEFAULT_GENERATE_ACTIONS; 64 boolean mNewInterruptionModel; 65 int mMaxMessagesToExtract = DEFAULT_MAX_MESSAGES_TO_EXTRACT; 66 int mMaxSuggestions = DEFAULT_MAX_SUGGESTIONS; 67 AssistantSettings(Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable)68 private AssistantSettings(Handler handler, ContentResolver resolver, int userId, 69 Runnable onUpdateRunnable) { 70 super(handler); 71 mHandler = handler; 72 mResolver = resolver; 73 mUserId = userId; 74 mOnUpdateRunnable = onUpdateRunnable; 75 } 76 createAndRegister( Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable)77 private static AssistantSettings createAndRegister( 78 Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable) { 79 AssistantSettings assistantSettings = 80 new AssistantSettings(handler, resolver, userId, onUpdateRunnable); 81 assistantSettings.register(); 82 assistantSettings.registerDeviceConfigs(); 83 return assistantSettings; 84 } 85 86 /** 87 * Creates an instance but doesn't register it as an observer. 88 */ 89 @VisibleForTesting createForTesting( Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable)90 protected static AssistantSettings createForTesting( 91 Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable) { 92 return new AssistantSettings(handler, resolver, userId, onUpdateRunnable); 93 } 94 register()95 private void register() { 96 mResolver.registerContentObserver( 97 DISMISS_TO_VIEW_RATIO_LIMIT_URI, false, this, mUserId); 98 mResolver.registerContentObserver(STREAK_LIMIT_URI, false, this, mUserId); 99 100 // Update all uris on creation. 101 update(null); 102 } 103 registerDeviceConfigs()104 private void registerDeviceConfigs() { 105 DeviceConfig.addOnPropertiesChangedListener( 106 DeviceConfig.NAMESPACE_SYSTEMUI, 107 this::postToHandler, 108 (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace())); 109 110 // Update the fields in this class from the current state of the device config. 111 updateFromDeviceConfigFlags(); 112 } 113 postToHandler(Runnable r)114 private void postToHandler(Runnable r) { 115 this.mHandler.post(r); 116 } 117 118 @VisibleForTesting onDeviceConfigPropertiesChanged(String namespace)119 void onDeviceConfigPropertiesChanged(String namespace) { 120 if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) { 121 Log.e(LOG_TAG, "Received update from DeviceConfig for unrelated namespace: " 122 + namespace); 123 return; 124 } 125 126 updateFromDeviceConfigFlags(); 127 } 128 updateFromDeviceConfigFlags()129 private void updateFromDeviceConfigFlags() { 130 mGenerateReplies = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, 131 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, DEFAULT_GENERATE_REPLIES); 132 133 mGenerateActions = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, 134 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, DEFAULT_GENERATE_ACTIONS); 135 136 mMaxMessagesToExtract = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, 137 SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT, 138 DEFAULT_MAX_MESSAGES_TO_EXTRACT); 139 140 mMaxSuggestions = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, 141 SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS, DEFAULT_MAX_SUGGESTIONS); 142 143 mOnUpdateRunnable.run(); 144 } 145 146 @Override onChange(boolean selfChange, Uri uri)147 public void onChange(boolean selfChange, Uri uri) { 148 update(uri); 149 } 150 update(Uri uri)151 private void update(Uri uri) { 152 if (uri == null || DISMISS_TO_VIEW_RATIO_LIMIT_URI.equals(uri)) { 153 mDismissToViewRatioLimit = Settings.Global.getFloat( 154 mResolver, Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT, 155 ChannelImpressions.DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT); 156 } 157 if (uri == null || STREAK_LIMIT_URI.equals(uri)) { 158 mStreakLimit = Settings.Global.getInt( 159 mResolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, 160 ChannelImpressions.DEFAULT_STREAK_LIMIT); 161 } 162 if (uri == null || NOTIFICATION_NEW_INTERRUPTION_MODEL_URI.equals(uri)) { 163 int mNewInterruptionModelInt = Settings.Secure.getInt( 164 mResolver, Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 165 DEFAULT_NEW_INTERRUPTION_MODEL_INT); 166 mNewInterruptionModel = mNewInterruptionModelInt == 1; 167 } 168 169 mOnUpdateRunnable.run(); 170 } 171 172 public interface Factory { createAndRegister(Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable)173 AssistantSettings createAndRegister(Handler handler, ContentResolver resolver, int userId, 174 Runnable onUpdateRunnable); 175 } 176 } 177