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.defaultapps; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.os.UserHandle; 22 import android.text.TextUtils; 23 24 import androidx.annotation.NonNull; 25 import androidx.preference.TwoStatePreference; 26 27 import com.android.car.settings.R; 28 import com.android.car.settings.common.ConfirmationDialogFragment; 29 import com.android.car.settings.common.FragmentController; 30 import com.android.car.settings.common.GroupSelectionPreferenceController; 31 import com.android.car.settings.common.Logger; 32 import com.android.car.ui.preference.CarUiRadioButtonPreference; 33 import com.android.settingslib.applications.DefaultAppInfo; 34 35 import java.util.ArrayList; 36 import java.util.HashMap; 37 import java.util.List; 38 import java.util.Map; 39 40 /** Defines the shared logic in picking a default application. */ 41 public abstract class DefaultAppsPickerBasePreferenceController extends 42 GroupSelectionPreferenceController { 43 44 private static final Logger LOG = new Logger(DefaultAppsPickerBasePreferenceController.class); 45 private static final String DIALOG_KEY_ARG = "key_arg"; 46 protected static final String NONE_PREFERENCE_KEY = ""; 47 48 private final Map<String, DefaultAppInfo> mDefaultAppInfoMap = new HashMap<>(); 49 private final ConfirmationDialogFragment.ConfirmListener mConfirmListener = arguments -> { 50 setCurrentDefault(arguments.getString(DIALOG_KEY_ARG)); 51 notifyCheckedKeyChanged(); 52 }; 53 DefaultAppsPickerBasePreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)54 public DefaultAppsPickerBasePreferenceController(Context context, String preferenceKey, 55 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 56 super(context, preferenceKey, fragmentController, uxRestrictions); 57 } 58 59 @Override onCreateInternal()60 protected void onCreateInternal() { 61 ConfirmationDialogFragment.resetListeners( 62 (ConfirmationDialogFragment) getFragmentController().findDialogByTag( 63 ConfirmationDialogFragment.TAG), 64 mConfirmListener, 65 /* rejectListener= */ null, 66 /* neutralListener= */ null); 67 } 68 69 @Override 70 @NonNull getGroupPreferences()71 protected List<TwoStatePreference> getGroupPreferences() { 72 List<TwoStatePreference> entries = new ArrayList<>(); 73 if (includeNonePreference()) { 74 entries.add(createNoneOption()); 75 } 76 77 List<DefaultAppInfo> currentCandidates = getCandidates(); 78 if (currentCandidates != null) { 79 for (DefaultAppInfo info : currentCandidates) { 80 mDefaultAppInfoMap.put(info.getKey(), info); 81 entries.add(createOption(info)); 82 } 83 } else { 84 LOG.i("no candidate provided"); 85 } 86 87 return entries; 88 } 89 90 @Override handleGroupItemSelected(TwoStatePreference preference)91 protected final boolean handleGroupItemSelected(TwoStatePreference preference) { 92 String selectedKey = preference.getKey(); 93 if (TextUtils.equals(selectedKey, getCurrentCheckedKey())) { 94 return false; 95 } 96 97 CharSequence message = getConfirmationMessage(mDefaultAppInfoMap.get(selectedKey)); 98 if (!TextUtils.isEmpty(message)) { 99 ConfirmationDialogFragment dialogFragment = 100 new ConfirmationDialogFragment.Builder(getContext()) 101 .setMessage(message.toString()) 102 .setPositiveButton(android.R.string.ok, mConfirmListener) 103 .setNegativeButton(android.R.string.cancel, /* rejectListener= */ null) 104 .addArgumentString(DIALOG_KEY_ARG, selectedKey) 105 .build(); 106 getFragmentController().showDialog(dialogFragment, ConfirmationDialogFragment.TAG); 107 return false; 108 } 109 110 setCurrentDefault(selectedKey); 111 return true; 112 } 113 114 @Override getCurrentCheckedKey()115 protected final String getCurrentCheckedKey() { 116 return getCurrentDefaultKey(); 117 } 118 createOption(DefaultAppInfo info)119 protected TwoStatePreference createOption(DefaultAppInfo info) { 120 CarUiRadioButtonPreference preference = new CarUiRadioButtonPreference(getContext()); 121 preference.setKey(info.getKey()); 122 preference.setTitle(info.loadLabel()); 123 preference.setIcon(DefaultAppUtils.getSafeIcon(info.loadIcon(), 124 getContext().getResources().getInteger(R.integer.default_app_safe_icon_size))); 125 preference.setEnabled(info.enabled); 126 return preference; 127 } 128 129 /** Gets all of the candidates that should be considered when choosing a default application. */ 130 @NonNull getCandidates()131 protected abstract List<DefaultAppInfo> getCandidates(); 132 133 /** Gets the key of the currently selected candidate. */ getCurrentDefaultKey()134 protected abstract String getCurrentDefaultKey(); 135 136 /** 137 * Sets the key of the currently selected candidate. The implementation of this method should 138 * modify the value returned by {@link #getCurrentDefaultKey()}}. 139 * 140 * @param key represents the key from {@link DefaultAppInfo} which should mark the default 141 * application. 142 */ setCurrentDefault(String key)143 protected abstract void setCurrentDefault(String key); 144 145 /** 146 * Defines the warning dialog message to be shown when a default app is selected. 147 */ getConfirmationMessage(DefaultAppInfo info)148 protected CharSequence getConfirmationMessage(DefaultAppInfo info) { 149 return null; 150 } 151 152 /** Gets the current process user id. */ getCurrentProcessUserId()153 protected int getCurrentProcessUserId() { 154 return UserHandle.myUserId(); 155 } 156 157 /** 158 * Determines whether the list of default apps should include "none". Implementation classes can 159 * override this value to {@code false} in order to remove the "none" preference. 160 */ includeNonePreference()161 protected boolean includeNonePreference() { 162 return true; 163 } 164 createNoneOption()165 private CarUiRadioButtonPreference createNoneOption() { 166 CarUiRadioButtonPreference preference = new CarUiRadioButtonPreference(getContext()); 167 preference.setKey(NONE_PREFERENCE_KEY); 168 preference.setTitle(R.string.app_list_preference_none); 169 preference.setIcon(R.drawable.ic_remove_circle); 170 return preference; 171 } 172 } 173