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