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