• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.about;
18 
19 import static com.android.tv.settings.library.overlay.FlavorUtils.FLAVOR_CLASSIC;
20 import static com.android.tv.settings.library.overlay.FlavorUtils.FLAVOR_TWO_PANEL;
21 import static com.android.tv.settings.library.overlay.FlavorUtils.FLAVOR_VENDOR;
22 import static com.android.tv.settings.library.overlay.FlavorUtils.FLAVOR_X;
23 import static com.android.tv.settings.util.InstrumentationUtils.logEntrySelected;
24 
25 import android.app.tvsettings.TvSettingsEnums;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.pm.ResolveInfo;
31 import android.icu.text.MessageFormat;
32 import android.os.Build;
33 import android.os.Bundle;
34 import android.os.PersistableBundle;
35 import android.os.SELinux;
36 import android.os.SystemClock;
37 import android.os.SystemProperties;
38 import android.os.UserHandle;
39 import android.os.UserManager;
40 import android.provider.Settings;
41 import android.sysprop.TelephonyProperties;
42 import android.telephony.CarrierConfigManager;
43 import android.text.TextUtils;
44 import android.util.Log;
45 import android.widget.Toast;
46 
47 import androidx.annotation.Keep;
48 import androidx.annotation.Nullable;
49 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
50 import androidx.preference.Preference;
51 import androidx.preference.PreferenceScreen;
52 
53 import com.android.settingslib.DeviceInfoUtils;
54 import com.android.settingslib.RestrictedLockUtils;
55 import com.android.settingslib.RestrictedLockUtilsInternal;
56 import com.android.settingslib.Utils;
57 import com.android.settingslib.development.DevelopmentSettingsEnabler;
58 import com.android.tv.settings.MainFragment;
59 import com.android.tv.settings.PreferenceUtils;
60 import com.android.tv.settings.R;
61 import com.android.tv.settings.SettingsPreferenceFragment;
62 import com.android.tv.settings.library.overlay.FlavorUtils;
63 import com.android.tv.settings.name.DeviceManager;
64 import com.android.tv.twopanelsettings.slices.CustomContentDescriptionPreference;
65 
66 import java.util.HashMap;
67 import java.util.Locale;
68 import java.util.Map;
69 import java.util.stream.Collectors;
70 
71 /**
72  * The "About" screen in TV settings.
73  */
74 @Keep
75 public class AboutFragment extends SettingsPreferenceFragment {
76     private static final String TAG = "AboutFragment";
77 
78     private static final String KEY_MANUAL = "manual";
79     private static final String KEY_REGULATORY_INFO = "regulatory_info";
80     private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
81     private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal";
82     private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux";
83     private static final String KEY_KERNEL_VERSION = "kernel_version";
84     private static final String KEY_BUILD_NUMBER = "build_number";
85     private static final String KEY_DEVICE_MODEL = "device_model";
86     private static final String KEY_SELINUX_STATUS = "selinux_status";
87     private static final String KEY_BASEBAND_VERSION = "baseband_version";
88     private static final String KEY_FIRMWARE_VERSION = "firmware_version";
89     private static final String KEY_SECURITY_PATCH = "security_patch";
90     private static final String KEY_UPDATE_SETTING = "additional_system_update_settings";
91     private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id";
92     private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid";
93     private static final String KEY_DEVICE_FEEDBACK = "device_feedback";
94     private static final String KEY_SAFETY_LEGAL = "safetylegal";
95     private static final String KEY_DEVICE_NAME = "device_name";
96     private static final String KEY_TUTORIALS = "tutorials";
97     private static final String KEY_RESET = "reset";
98     private static final String KEY_RESET_OPTIONS = "reset_options";
99 
100     static final int TAPS_TO_BE_A_DEVELOPER = 7;
101 
102     long[] mHits = new long[3];
103     int mDevHitCountdown;
104     Toast mDevHitToast;
105 
106     private UserManager mUm;
107 
108     private final BroadcastReceiver mDeviceNameReceiver = new BroadcastReceiver() {
109         @Override
110         public void onReceive(Context context, Intent intent) {
111             refreshDeviceName();
112         }
113     };
114 
newInstance()115     public static AboutFragment newInstance() {
116         return new AboutFragment();
117     }
118 
119     @Override
onCreate(Bundle savedInstanceState)120     public void onCreate(Bundle savedInstanceState) {
121         mUm = UserManager.get(getActivity());
122 
123         super.onCreate(savedInstanceState);
124     }
125 
getPreferenceScreenResId()126     private int getPreferenceScreenResId() {
127         switch (FlavorUtils.getFlavor(getContext())) {
128             case FLAVOR_CLASSIC:
129             case FLAVOR_TWO_PANEL:
130                 return R.xml.device_info_settings;
131             case FLAVOR_X:
132                 return R.xml.device_info_settings_x;
133             case FLAVOR_VENDOR:
134                 return R.xml.device_info_settings_vendor;
135             default:
136                 return R.xml.device_info_settings;
137         }
138     }
139 
140     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)141     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
142         setPreferencesFromResource(getPreferenceScreenResId(), null);
143         final PreferenceScreen screen = getPreferenceScreen();
144 
145         refreshDeviceName();
146         final Preference deviceNamePref = findPreference(KEY_DEVICE_NAME);
147         PreferenceUtils.resolveSystemActivityOrRemove(getActivity(), screen, deviceNamePref, 0);
148 
149         final Preference firmwareVersionPref = findPreference(KEY_FIRMWARE_VERSION);
150         firmwareVersionPref.setSummary(Build.VERSION.RELEASE_OR_CODENAME);
151         firmwareVersionPref.setEnabled(true);
152 
153         final Preference securityPatchPref = findPreference(KEY_SECURITY_PATCH);
154         final String patch = DeviceInfoUtils.getSecurityPatch();
155         if (!TextUtils.isEmpty(patch)) {
156             securityPatchPref.setSummary(patch);
157         } else {
158             removePreference(securityPatchPref);
159         }
160 
161         String basebandVersion = TelephonyProperties.baseband_version().stream()
162                 .map(x -> x == null ? "" : x)
163                 .collect(Collectors.joining(","));
164 
165         if (basebandVersion.isEmpty()) {
166             basebandVersion = getResources().getString(R.string.device_info_default);
167         }
168 
169         findPreference(KEY_BASEBAND_VERSION).setSummary(basebandVersion);
170         findPreference(KEY_DEVICE_MODEL).setSummary(Build.MODEL + DeviceInfoUtils.getMsvSuffix());
171         findPreference(KEY_EQUIPMENT_ID)
172                 .setSummary(getSystemPropertySummary(PROPERTY_EQUIPMENT_ID));
173 
174         final Preference buildNumberPref = findPreference(KEY_BUILD_NUMBER);
175         buildNumberPref.setSummary(Build.DISPLAY);
176         buildNumberPref.setEnabled(true);
177         findPreference(KEY_KERNEL_VERSION)
178                 .setSummary(DeviceInfoUtils.getFormattedKernelVersion(getContext()));
179 
180         final Preference selinuxPref = findPreference(KEY_SELINUX_STATUS);
181         if (!SELinux.isSELinuxEnabled()) {
182             selinuxPref.setSummary(R.string.selinux_status_disabled);
183         } else if (!SELinux.isSELinuxEnforced()) {
184             selinuxPref.setSummary(R.string.selinux_status_permissive);
185         }
186 
187         // Remove selinux information if property is not present
188         if (TextUtils.isEmpty(SystemProperties.get(PROPERTY_SELINUX_STATUS))) {
189             removePreference(selinuxPref);
190         }
191 
192         // Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set
193         if (TextUtils.isEmpty(SystemProperties.get(PROPERTY_URL_SAFETYLEGAL))) {
194             removePreference(findPreference(KEY_SAFETY_LEGAL));
195         }
196 
197         // Remove Equipment id preference if FCC ID is not set by RIL
198         if (TextUtils.isEmpty(SystemProperties.get(PROPERTY_EQUIPMENT_ID))) {
199             removePreference(findPreference(KEY_EQUIPMENT_ID));
200         }
201 
202         // Remove Baseband version if wifi-only device
203         if (Utils.isWifiOnly(getActivity())) {
204             removePreference(findPreference(KEY_BASEBAND_VERSION));
205         }
206 
207         // Dont show feedback option if there is no reporter.
208         if (TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(getActivity()))) {
209             removePreference(findPreference(KEY_DEVICE_FEEDBACK));
210         }
211 
212         final Preference resetPreference = findPreference(KEY_RESET);
213         if (resetPreference instanceof CustomContentDescriptionPreference) {
214             ((CustomContentDescriptionPreference) resetPreference).setContentDescription(
215                     getResources().getString(R.string.factory_reset_content_description));
216         }
217 
218         // Don't show the reset options if factory reset is restricted
219         final Preference resetOptionsPreference = findPreference(KEY_RESET_OPTIONS);
220         if (resetOptionsPreference != null
221                 && RestrictedLockUtilsInternal.checkIfRestrictionEnforced(getContext(),
222                 UserManager.DISALLOW_FACTORY_RESET, UserHandle.myUserId()) != null) {
223             resetOptionsPreference.setFragment(null);
224         }
225 
226         final Preference updateSettingsPref = findPreference(KEY_SYSTEM_UPDATE_SETTINGS);
227         if (updateSettingsPref instanceof CustomContentDescriptionPreference) {
228             ((CustomContentDescriptionPreference) updateSettingsPref).setContentDescription(
229                     getResources().getString(R.string.system_update_content_description));
230         }
231 
232         if (mUm.isAdminUser()) {
233             final Intent systemUpdateIntent = new Intent(Settings.ACTION_SYSTEM_UPDATE_SETTINGS);
234             final ResolveInfo info =
235                     MainFragment.systemIntentIsHandled(getContext(), systemUpdateIntent);
236             if (info == null) {
237                 removePreference(updateSettingsPref);
238             } else {
239                 updateSettingsPref.setTitle(info.loadLabel(getContext().getPackageManager()));
240             }
241         } else if (updateSettingsPref != null) {
242             // Remove for secondary users
243             removePreference(updateSettingsPref);
244         }
245 
246         // Read platform settings for additional system update setting
247         if (!getResources().getBoolean(R.bool.config_additional_system_update_setting_enable)) {
248             removePreference(findPreference(KEY_UPDATE_SETTING));
249         }
250 
251         // Remove manual entry if none present.
252         if (!getResources().getBoolean(R.bool.config_show_manual)) {
253             removePreference(findPreference(KEY_MANUAL));
254         }
255 
256         // Remove regulatory information if none present.
257         final Preference regulatoryPref = findPreference(KEY_REGULATORY_INFO);
258         PreferenceUtils.resolveSystemActivityOrRemove(getActivity(), screen, regulatoryPref, 0);
259 
260         updateTutorials();
261     }
262 
removePreference(@ullable Preference preference)263     private void removePreference(@Nullable Preference preference) {
264         if (preference != null) {
265             getPreferenceScreen().removePreference(preference);
266         }
267     }
268 
269     @Override
onStart()270     public void onStart() {
271         super.onStart();
272         refreshDeviceName();
273 
274         LocalBroadcastManager.getInstance(getContext()).registerReceiver(mDeviceNameReceiver,
275                 new IntentFilter(DeviceManager.ACTION_DEVICE_NAME_UPDATE));
276     }
277 
278     @Override
onResume()279     public void onResume() {
280         super.onResume();
281         mDevHitCountdown = DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext())
282                 ? -1 : TAPS_TO_BE_A_DEVELOPER;
283         mDevHitToast = null;
284     }
285 
286     @Override
onStop()287     public void onStop() {
288         super.onStop();
289         LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mDeviceNameReceiver);
290     }
291 
refreshDeviceName()292     private void refreshDeviceName() {
293         final Preference deviceNamePref = findPreference(KEY_DEVICE_NAME);
294         if (deviceNamePref != null) {
295             deviceNamePref.setSummary(DeviceManager.getDeviceName(getActivity()));
296         }
297     }
298 
299     @Override
onPreferenceTreeClick(Preference preference)300     public boolean onPreferenceTreeClick(Preference preference) {
301         switch (preference.getKey()) {
302             case KEY_FIRMWARE_VERSION:
303                 System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
304                 mHits[mHits.length - 1] = SystemClock.uptimeMillis();
305                 if (mHits[0] >= (SystemClock.uptimeMillis() - 500)) {
306                     if (mUm.hasUserRestriction(UserManager.DISALLOW_FUN)) {
307                         final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal
308                                 .checkIfRestrictionEnforced(getContext(), UserManager.DISALLOW_FUN,
309                                         UserHandle.myUserId());
310                         if (admin != null) {
311                             RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
312                                     admin);
313                         }
314 
315                         Log.d(TAG, "Sorry, no fun for you!");
316                         return false;
317                     }
318 
319                     Intent intent = new Intent(Intent.ACTION_MAIN);
320                     intent.setClassName("android",
321                             com.android.internal.app.PlatLogoActivity.class.getName());
322                     try {
323                         startActivity(intent);
324                     } catch (Exception e) {
325                         Log.e(TAG, "Unable to start activity " + intent.toString());
326                     }
327                 }
328                 break;
329             case KEY_BUILD_NUMBER:
330                 logEntrySelected(TvSettingsEnums.SYSTEM_ABOUT_BUILD);
331                 // Don't enable developer options for secondary users.
332                 if (!mUm.isAdminUser()) {
333                     return true;
334                 }
335 
336                 if (mUm.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)) {
337                     final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal
338                             .checkIfRestrictionEnforced(getContext(),
339                                     UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.myUserId());
340                     if (admin != null) {
341                         RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), admin);
342                     }
343                     return true;
344                 }
345 
346                 if (mDevHitCountdown > 0) {
347                     mDevHitCountdown--;
348                     if (mDevHitCountdown == 0) {
349                         DevelopmentSettingsEnabler
350                                 .setDevelopmentSettingsEnabled(getContext(), true);
351                         if (mDevHitToast != null) {
352                             mDevHitToast.cancel();
353                         }
354                         mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_on,
355                                 Toast.LENGTH_LONG);
356                         mDevHitToast.show();
357                         // This is good time to index the Developer Options
358 //                    Index.getInstance(
359 //                            getActivity().getApplicationContext()).updateFromClassNameResource(
360 //                            DevelopmentSettings.class.getName(), true, true);
361                     } else if (mDevHitCountdown > 0
362                             && mDevHitCountdown < (TAPS_TO_BE_A_DEVELOPER - 2)) {
363                         if (mDevHitToast != null) {
364                             mDevHitToast.cancel();
365                         }
366                         MessageFormat msgFormat = new MessageFormat(
367                                 getResources().getString(R.string.show_dev_countdown),
368                                 Locale.getDefault());
369                         Map<String, Object> arguments = new HashMap<>();
370                         arguments.put("count", mDevHitCountdown);
371                         mDevHitToast = Toast.makeText(
372                                 getActivity(), msgFormat.format(arguments), Toast.LENGTH_SHORT);
373                         mDevHitToast.show();
374                     }
375                 } else if (mDevHitCountdown < 0) {
376                     if (mDevHitToast != null) {
377                         mDevHitToast.cancel();
378                     }
379                     mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_already,
380                             Toast.LENGTH_LONG);
381                     mDevHitToast.show();
382                 }
383                 break;
384             case KEY_DEVICE_FEEDBACK:
385                 sendFeedback();
386                 break;
387             case KEY_SYSTEM_UPDATE_SETTINGS:
388                 logEntrySelected(TvSettingsEnums.SYSTEM_ABOUT_SYSTEM_UPDATE);
389                 CarrierConfigManager configManager = (CarrierConfigManager)
390                         getActivity().getSystemService(Context.CARRIER_CONFIG_SERVICE);
391                 PersistableBundle b = configManager.getConfig();
392                 if (b != null &&
393                         b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
394                     ciActionOnSysUpdate(b);
395                 }
396                 startActivity(new Intent(Settings.ACTION_SYSTEM_UPDATE_SETTINGS));
397                 break;
398             case KEY_DEVICE_NAME:
399                 logEntrySelected(TvSettingsEnums.SYSTEM_ABOUT_DEVICE_NAME);
400                 break;
401             case KEY_RESET:
402                 logEntrySelected(TvSettingsEnums.SYSTEM_ABOUT_FACTORY_RESET);
403                 Intent factoryResetIntent = new Intent();
404                 factoryResetIntent.setClassName(
405                         "com.android.tv.settings",
406                         "com.android.tv.settings.device.storage.ResetActivity");
407                 startActivity(factoryResetIntent);
408                 break;
409         }
410         return super.onPreferenceTreeClick(preference);
411     }
412 
413     /**
414      * Trigger client initiated action (send intent) on system update
415      */
ciActionOnSysUpdate(PersistableBundle b)416     private void ciActionOnSysUpdate(PersistableBundle b) {
417         String intentStr = b.getString(CarrierConfigManager.
418                 KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING);
419         if (!TextUtils.isEmpty(intentStr)) {
420             String extra = b.getString(CarrierConfigManager.
421                     KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING);
422             String extraVal = b.getString(CarrierConfigManager.
423                     KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING);
424 
425             Intent intent = new Intent(intentStr);
426             if (!TextUtils.isEmpty(extra)) {
427                 intent.putExtra(extra, extraVal);
428             }
429             Log.d(TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr +
430                     " with extra " + extra + ", " + extraVal);
431             getActivity().getApplicationContext().sendBroadcast(intent);
432         }
433     }
434 
getSystemPropertySummary(String property)435     private String getSystemPropertySummary(String property) {
436         return SystemProperties.get(property,
437                 getResources().getString(R.string.device_info_default));
438     }
439 
sendFeedback()440     private void sendFeedback() {
441         String reporterPackage = DeviceInfoUtils.getFeedbackReporterPackage(getActivity());
442         if (TextUtils.isEmpty(reporterPackage)) {
443             return;
444         }
445         Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
446         intent.setPackage(reporterPackage);
447         startActivityForResult(intent, 0);
448     }
449 
updateTutorials()450     private void updateTutorials() {
451         final Preference deviceTutorialsPref = findPreference(KEY_TUTORIALS);
452         if (deviceTutorialsPref != null) {
453             final ResolveInfo info = MainFragment.systemIntentIsHandled(getContext(),
454                     deviceTutorialsPref.getIntent());
455             deviceTutorialsPref.setVisible(info != null);
456             if (info != null) {
457                 deviceTutorialsPref.setTitle(info.loadLabel(getContext().getPackageManager()));
458             }
459         }
460     }
461 
462     @Override
getPageId()463     protected int getPageId() {
464         return TvSettingsEnums.SYSTEM_ABOUT;
465     }
466 }
467