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