1 /* 2 * Copyright (C) 2019 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.car.settings.applications.assist; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.database.ContentObserver; 23 import android.net.Uri; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.os.UserHandle; 27 import android.provider.Settings; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.preference.TwoStatePreference; 31 32 import com.android.car.settings.common.FragmentController; 33 import com.android.car.settings.common.PreferenceController; 34 import com.android.internal.app.AssistUtils; 35 36 import java.util.List; 37 38 /** Common logic for preference controllers that configure the assistant's behavior. */ 39 public abstract class AssistConfigBasePreferenceController extends 40 PreferenceController<TwoStatePreference> { 41 42 final SettingObserver mSettingObserver; 43 private final AssistUtils mAssistUtils; 44 AssistConfigBasePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)45 public AssistConfigBasePreferenceController(Context context, String preferenceKey, 46 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 47 this(context, preferenceKey, fragmentController, uxRestrictions, new AssistUtils(context)); 48 } 49 50 @VisibleForTesting AssistConfigBasePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, AssistUtils assistUtils)51 AssistConfigBasePreferenceController(Context context, String preferenceKey, 52 FragmentController fragmentController, CarUxRestrictions uxRestrictions, 53 AssistUtils assistUtils) { 54 super(context, preferenceKey, fragmentController, uxRestrictions); 55 mAssistUtils = assistUtils; 56 mSettingObserver = new SettingObserver(getSettingUris(), this::refreshUi); 57 } 58 59 @Override getPreferenceType()60 protected Class<TwoStatePreference> getPreferenceType() { 61 return TwoStatePreference.class; 62 } 63 64 @Override getDefaultAvailabilityStatus()65 protected int getDefaultAvailabilityStatus() { 66 return mAssistUtils.getAssistComponentForUser( 67 UserHandle.myUserId()) != null ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; 68 } 69 70 @Override onStartInternal()71 protected void onStartInternal() { 72 mSettingObserver.register(getContext().getContentResolver(), true); 73 } 74 75 @Override onStopInternal()76 protected void onStopInternal() { 77 mSettingObserver.register(getContext().getContentResolver(), false); 78 } 79 80 /** Gets the Setting Uris that should be observed */ getSettingUris()81 protected abstract List<Uri> getSettingUris(); 82 83 /** 84 * Creates an observer that listens for changes to {@link Settings.Secure#ASSISTANT} as well as 85 * any other URI defined by {@link #getSettingUris()}. 86 */ 87 @VisibleForTesting 88 static class SettingObserver extends ContentObserver { 89 private static final Uri ASSIST_URI = Settings.Secure.getUriFor(Settings.Secure.ASSISTANT); 90 private final List<Uri> mUriList; 91 private final Runnable mSettingChangeListener; 92 SettingObserver(List<Uri> uriList, Runnable settingChangeListener)93 SettingObserver(List<Uri> uriList, Runnable settingChangeListener) { 94 super(new Handler(Looper.getMainLooper())); 95 mUriList = uriList; 96 mSettingChangeListener = settingChangeListener; 97 } 98 99 /** Registers or unregisters this observer to the given content resolver. */ register(ContentResolver cr, boolean register)100 void register(ContentResolver cr, boolean register) { 101 if (register) { 102 cr.registerContentObserver(ASSIST_URI, /* notifyForDescendants= */ false, 103 /* observer= */ this); 104 if (mUriList != null) { 105 for (Uri uri : mUriList) { 106 cr.registerContentObserver(uri, /* notifyForDescendants= */ false, 107 /* observer= */ this); 108 } 109 } 110 } else { 111 cr.unregisterContentObserver(this); 112 } 113 } 114 115 @Override onChange(boolean selfChange, Uri uri)116 public void onChange(boolean selfChange, Uri uri) { 117 super.onChange(selfChange, uri); 118 119 if (shouldUpdatePreference(uri)) { 120 mSettingChangeListener.run(); 121 } 122 } 123 shouldUpdatePreference(Uri uri)124 private boolean shouldUpdatePreference(Uri uri) { 125 return ASSIST_URI.equals(uri) || (mUriList != null && mUriList.contains(uri)); 126 } 127 } 128 } 129