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