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 com.android.tv.settings.device; 18 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.content.pm.ResolveInfo; 22 import android.content.res.Resources; 23 import android.media.tv.TvInputInfo; 24 import android.media.tv.TvInputManager; 25 import android.os.Bundle; 26 import android.os.UserHandle; 27 import android.text.TextUtils; 28 import android.util.Log; 29 import android.view.inputmethod.InputMethodInfo; 30 31 import androidx.annotation.Keep; 32 import androidx.annotation.VisibleForTesting; 33 import androidx.preference.Preference; 34 35 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 36 import com.android.settingslib.applications.DefaultAppInfo; 37 import com.android.settingslib.development.DevelopmentSettingsEnabler; 38 import com.android.tv.settings.MainFragment; 39 import com.android.tv.settings.R; 40 import com.android.tv.settings.SettingsPreferenceFragment; 41 import com.android.tv.settings.autofill.AutofillHelper; 42 import com.android.tv.settings.device.sound.SoundFragment; 43 import com.android.tv.settings.inputmethod.InputMethodHelper; 44 import com.android.tv.settings.system.SecurityFragment; 45 46 import java.util.List; 47 48 /** 49 * The "Device Preferences" screen in TV settings. 50 */ 51 @Keep 52 public class DevicePrefFragment extends SettingsPreferenceFragment { 53 private static final String TAG = "DeviceFragment"; 54 55 @VisibleForTesting 56 static final String KEY_DEVELOPER = "developer"; 57 private static final String KEY_USAGE = "usageAndDiag"; 58 private static final String KEY_INPUTS = "inputs"; 59 private static final String KEY_SOUNDS = "sound_effects"; 60 @VisibleForTesting 61 static final String KEY_CAST_SETTINGS = "cast"; 62 private static final String KEY_GOOGLE_SETTINGS = "google_settings"; 63 private static final String KEY_HOME_SETTINGS = "home"; 64 @VisibleForTesting 65 static final String KEY_KEYBOARD = "keyboard"; 66 67 private Preference mSoundsPref; 68 private boolean mInputSettingNeeded; 69 private PackageManager mPm; 70 71 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)72 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 73 if (isRestricted()) { 74 setPreferencesFromResource(R.xml.device_restricted, null); 75 } else { 76 setPreferencesFromResource(R.xml.device, null); 77 } 78 mSoundsPref = findPreference(KEY_SOUNDS); 79 final Preference inputPref = findPreference(KEY_INPUTS); 80 if (inputPref != null) { 81 inputPref.setVisible(mInputSettingNeeded); 82 } 83 } 84 85 @Override onCreate(Bundle savedInstanceState)86 public void onCreate(Bundle savedInstanceState) { 87 final TvInputManager manager = (TvInputManager) getContext().getSystemService( 88 Context.TV_INPUT_SERVICE); 89 if (manager != null) { 90 for (final TvInputInfo input : manager.getTvInputList()) { 91 if (input.isPassthroughInput()) { 92 mInputSettingNeeded = true; 93 } 94 } 95 } 96 super.onCreate(savedInstanceState); 97 } 98 99 @Override onAttach(Context context)100 public void onAttach(Context context) { 101 super.onAttach(context); 102 mPm = context.getPackageManager(); 103 } 104 105 @Override onResume()106 public void onResume() { 107 super.onResume(); 108 109 updateDeveloperOptions(); 110 updateSounds(); 111 updateGoogleSettings(); 112 updateCastSettings(); 113 updateKeyboardAutofillSettings(); 114 hideIfIntentUnhandled(findPreference(KEY_HOME_SETTINGS)); 115 hideIfIntentUnhandled(findPreference(KEY_CAST_SETTINGS)); 116 hideIfIntentUnhandled(findPreference(KEY_USAGE)); 117 } 118 119 @Override getMetricsCategory()120 public int getMetricsCategory() { 121 return MetricsEvent.SETTINGS_TV_DEVICE_CATEGORY; 122 } 123 hideIfIntentUnhandled(Preference preference)124 private void hideIfIntentUnhandled(Preference preference) { 125 if (preference == null || !preference.isVisible()) { 126 return; 127 } 128 preference.setVisible( 129 MainFragment.systemIntentIsHandled(getContext(), preference.getIntent()) != null); 130 } 131 isRestricted()132 private boolean isRestricted() { 133 return SecurityFragment.isRestrictedProfileInEffect(getContext()); 134 } 135 136 @VisibleForTesting updateDeveloperOptions()137 void updateDeveloperOptions() { 138 final Preference developerPref = findPreference(KEY_DEVELOPER); 139 if (developerPref == null) { 140 return; 141 } 142 143 developerPref.setVisible(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled( 144 getContext())); 145 } 146 updateSounds()147 private void updateSounds() { 148 if (mSoundsPref == null) { 149 return; 150 } 151 152 mSoundsPref.setIcon(SoundFragment.getSoundEffectsEnabled(getContext().getContentResolver()) 153 ? R.drawable.ic_volume_up : R.drawable.ic_volume_off); 154 } 155 updateGoogleSettings()156 private void updateGoogleSettings() { 157 final Preference googleSettingsPref = findPreference(KEY_GOOGLE_SETTINGS); 158 if (googleSettingsPref != null) { 159 final ResolveInfo info = MainFragment.systemIntentIsHandled(getContext(), 160 googleSettingsPref.getIntent()); 161 googleSettingsPref.setVisible(info != null); 162 if (info != null && info.activityInfo != null) { 163 googleSettingsPref.setIcon( 164 info.activityInfo.loadIcon(getContext().getPackageManager())); 165 googleSettingsPref.setTitle( 166 info.activityInfo.loadLabel(getContext().getPackageManager())); 167 } 168 } 169 } 170 171 @VisibleForTesting updateCastSettings()172 void updateCastSettings() { 173 final Preference castPref = findPreference(KEY_CAST_SETTINGS); 174 if (castPref != null) { 175 final ResolveInfo info = MainFragment.systemIntentIsHandled( 176 getContext(), castPref.getIntent()); 177 if (info != null) { 178 try { 179 final Context targetContext = getContext() 180 .createPackageContext(info.resolvePackageName != null 181 ? info.resolvePackageName : info.activityInfo.packageName, 0); 182 castPref.setIcon(targetContext.getDrawable(info.getIconResource())); 183 } catch (Resources.NotFoundException | PackageManager.NameNotFoundException 184 | SecurityException e) { 185 Log.e(TAG, "Cast settings icon not found", e); 186 } 187 castPref.setTitle(info.activityInfo.loadLabel(getContext().getPackageManager())); 188 } 189 } 190 } 191 192 @VisibleForTesting updateKeyboardAutofillSettings()193 void updateKeyboardAutofillSettings() { 194 final Preference keyboardPref = findPreference(KEY_KEYBOARD); 195 196 List<DefaultAppInfo> candidates = AutofillHelper.getAutofillCandidates(getContext(), 197 mPm, UserHandle.myUserId()); 198 199 // Switch title depends on whether there is autofill 200 if (candidates.isEmpty()) { 201 keyboardPref.setTitle(R.string.system_keyboard); 202 } else { 203 keyboardPref.setTitle(R.string.system_keyboard_autofill); 204 } 205 206 CharSequence summary = ""; 207 // append current keyboard to summary 208 String defaultImId = InputMethodHelper.getDefaultInputMethodId(getContext()); 209 if (!TextUtils.isEmpty(defaultImId)) { 210 InputMethodInfo info = InputMethodHelper.findInputMethod(defaultImId, 211 InputMethodHelper.getEnabledSystemInputMethodList(getContext())); 212 if (info != null) { 213 summary = info.loadLabel(getContext().getPackageManager()); 214 } 215 216 } 217 // append current autofill to summary 218 DefaultAppInfo appInfo = AutofillHelper.getCurrentAutofill(getContext(), candidates); 219 if (appInfo != null) { 220 CharSequence autofillInfo = appInfo.loadLabel(); 221 if (summary.length() > 0) { 222 getContext().getString(R.string.string_concat, summary, autofillInfo); 223 } else { 224 summary = autofillInfo; 225 } 226 } 227 keyboardPref.setSummary(summary); 228 } 229 } 230