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