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