1 /* 2 * Copyright (C) 2008 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.settings; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Build; 23 import android.os.Bundle; 24 import android.os.PersistableBundle; 25 import android.os.SELinux; 26 import android.os.SystemClock; 27 import android.os.SystemProperties; 28 import android.os.UserHandle; 29 import android.os.UserManager; 30 import android.provider.SearchIndexableResource; 31 import android.provider.Settings; 32 import android.support.v7.preference.Preference; 33 import android.support.v7.preference.PreferenceGroup; 34 import android.telephony.CarrierConfigManager; 35 import android.text.TextUtils; 36 import android.util.Log; 37 import android.widget.Toast; 38 39 import com.android.internal.logging.MetricsProto.MetricsEvent; 40 import com.android.settings.dashboard.SummaryLoader; 41 import com.android.settings.search.BaseSearchIndexProvider; 42 import com.android.settings.search.Index; 43 import com.android.settings.search.Indexable; 44 import com.android.settingslib.DeviceInfoUtils; 45 import com.android.settingslib.RestrictedLockUtils; 46 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.List; 50 51 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 52 53 public class DeviceInfoSettings extends SettingsPreferenceFragment implements Indexable { 54 55 private static final String LOG_TAG = "DeviceInfoSettings"; 56 57 private static final String KEY_MANUAL = "manual"; 58 private static final String KEY_REGULATORY_INFO = "regulatory_info"; 59 private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings"; 60 private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal"; 61 private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux"; 62 private static final String KEY_KERNEL_VERSION = "kernel_version"; 63 private static final String KEY_BUILD_NUMBER = "build_number"; 64 private static final String KEY_DEVICE_MODEL = "device_model"; 65 private static final String KEY_SELINUX_STATUS = "selinux_status"; 66 private static final String KEY_BASEBAND_VERSION = "baseband_version"; 67 private static final String KEY_FIRMWARE_VERSION = "firmware_version"; 68 private static final String KEY_SECURITY_PATCH = "security_patch"; 69 private static final String KEY_UPDATE_SETTING = "additional_system_update_settings"; 70 private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id"; 71 private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid"; 72 private static final String KEY_DEVICE_FEEDBACK = "device_feedback"; 73 private static final String KEY_SAFETY_LEGAL = "safetylegal"; 74 75 static final int TAPS_TO_BE_A_DEVELOPER = 7; 76 77 long[] mHits = new long[3]; 78 int mDevHitCountdown; 79 Toast mDevHitToast; 80 81 private UserManager mUm; 82 83 private EnforcedAdmin mFunDisallowedAdmin; 84 private boolean mFunDisallowedBySystem; 85 private EnforcedAdmin mDebuggingFeaturesDisallowedAdmin; 86 private boolean mDebuggingFeaturesDisallowedBySystem; 87 88 @Override 89 protected int getMetricsCategory() { 90 return MetricsEvent.DEVICEINFO; 91 } 92 93 @Override 94 protected int getHelpResource() { 95 return R.string.help_uri_about; 96 } 97 98 @Override 99 public void onCreate(Bundle icicle) { 100 super.onCreate(icicle); 101 mUm = UserManager.get(getActivity()); 102 103 addPreferencesFromResource(R.xml.device_info_settings); 104 105 setStringSummary(KEY_FIRMWARE_VERSION, Build.VERSION.RELEASE); 106 findPreference(KEY_FIRMWARE_VERSION).setEnabled(true); 107 108 final String patch = DeviceInfoUtils.getSecurityPatch(); 109 if (!TextUtils.isEmpty(patch)) { 110 setStringSummary(KEY_SECURITY_PATCH, patch); 111 } else { 112 getPreferenceScreen().removePreference(findPreference(KEY_SECURITY_PATCH)); 113 } 114 115 setValueSummary(KEY_BASEBAND_VERSION, "gsm.version.baseband"); 116 setStringSummary(KEY_DEVICE_MODEL, Build.MODEL + DeviceInfoUtils.getMsvSuffix()); 117 setValueSummary(KEY_EQUIPMENT_ID, PROPERTY_EQUIPMENT_ID); 118 setStringSummary(KEY_DEVICE_MODEL, Build.MODEL); 119 setStringSummary(KEY_BUILD_NUMBER, Build.DISPLAY); 120 findPreference(KEY_BUILD_NUMBER).setEnabled(true); 121 findPreference(KEY_KERNEL_VERSION).setSummary(DeviceInfoUtils.getFormattedKernelVersion()); 122 123 if (!SELinux.isSELinuxEnabled()) { 124 String status = getResources().getString(R.string.selinux_status_disabled); 125 setStringSummary(KEY_SELINUX_STATUS, status); 126 } else if (!SELinux.isSELinuxEnforced()) { 127 String status = getResources().getString(R.string.selinux_status_permissive); 128 setStringSummary(KEY_SELINUX_STATUS, status); 129 } 130 131 // Remove selinux information if property is not present 132 removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_SELINUX_STATUS, 133 PROPERTY_SELINUX_STATUS); 134 135 // Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set 136 removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_SAFETY_LEGAL, 137 PROPERTY_URL_SAFETYLEGAL); 138 139 // Remove Equipment id preference if FCC ID is not set by RIL 140 removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_EQUIPMENT_ID, 141 PROPERTY_EQUIPMENT_ID); 142 143 // Remove Baseband version if wifi-only device 144 if (Utils.isWifiOnly(getActivity())) { 145 getPreferenceScreen().removePreference(findPreference(KEY_BASEBAND_VERSION)); 146 } 147 148 // Dont show feedback option if there is no reporter. 149 if (TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(getActivity()))) { 150 getPreferenceScreen().removePreference(findPreference(KEY_DEVICE_FEEDBACK)); 151 } 152 153 /* 154 * Settings is a generic app and should not contain any device-specific 155 * info. 156 */ 157 final Activity act = getActivity(); 158 159 // These are contained by the root preference screen 160 PreferenceGroup parentPreference = getPreferenceScreen(); 161 162 if (mUm.isAdminUser()) { 163 Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, 164 KEY_SYSTEM_UPDATE_SETTINGS, 165 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY); 166 } else { 167 // Remove for secondary users 168 removePreference(KEY_SYSTEM_UPDATE_SETTINGS); 169 } 170 171 // Read platform settings for additional system update setting 172 removePreferenceIfBoolFalse(KEY_UPDATE_SETTING, 173 R.bool.config_additional_system_update_setting_enable); 174 175 // Remove manual entry if none present. 176 removePreferenceIfBoolFalse(KEY_MANUAL, R.bool.config_show_manual); 177 178 // Remove regulatory labels if no activity present to handle intent. 179 removePreferenceIfActivityMissing( 180 KEY_REGULATORY_INFO, Settings.ACTION_SHOW_REGULATORY_INFO); 181 182 removePreferenceIfActivityMissing( 183 "safety_info", "android.settings.SHOW_SAFETY_AND_REGULATORY_INFO"); 184 } 185 186 @Override 187 public void onResume() { 188 super.onResume(); 189 mDevHitCountdown = getActivity().getSharedPreferences(DevelopmentSettings.PREF_FILE, 190 Context.MODE_PRIVATE).getBoolean(DevelopmentSettings.PREF_SHOW, 191 android.os.Build.TYPE.equals("eng")) ? -1 : TAPS_TO_BE_A_DEVELOPER; 192 mDevHitToast = null; 193 mFunDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced( 194 getActivity(), UserManager.DISALLOW_FUN, UserHandle.myUserId()); 195 mFunDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( 196 getActivity(), UserManager.DISALLOW_FUN, UserHandle.myUserId()); 197 mDebuggingFeaturesDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced( 198 getActivity(), UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.myUserId()); 199 mDebuggingFeaturesDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( 200 getActivity(), UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.myUserId()); 201 } 202 203 @Override 204 public boolean onPreferenceTreeClick(Preference preference) { 205 if (preference.getKey().equals(KEY_FIRMWARE_VERSION)) { 206 System.arraycopy(mHits, 1, mHits, 0, mHits.length-1); 207 mHits[mHits.length-1] = SystemClock.uptimeMillis(); 208 if (mHits[0] >= (SystemClock.uptimeMillis()-500)) { 209 if (mUm.hasUserRestriction(UserManager.DISALLOW_FUN)) { 210 if (mFunDisallowedAdmin != null && !mFunDisallowedBySystem) { 211 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), 212 mFunDisallowedAdmin); 213 } 214 Log.d(LOG_TAG, "Sorry, no fun for you!"); 215 return false; 216 } 217 218 Intent intent = new Intent(Intent.ACTION_MAIN); 219 intent.setClassName("android", 220 com.android.internal.app.PlatLogoActivity.class.getName()); 221 try { 222 startActivity(intent); 223 } catch (Exception e) { 224 Log.e(LOG_TAG, "Unable to start activity " + intent.toString()); 225 } 226 } 227 } else if (preference.getKey().equals(KEY_BUILD_NUMBER)) { 228 // Don't enable developer options for secondary users. 229 if (!mUm.isAdminUser()) return true; 230 231 // Don't enable developer options until device has been provisioned 232 if (!Utils.isDeviceProvisioned(getActivity())) { 233 return true; 234 } 235 236 if (mUm.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)) { 237 if (mDebuggingFeaturesDisallowedAdmin != null && 238 !mDebuggingFeaturesDisallowedBySystem) { 239 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), 240 mDebuggingFeaturesDisallowedAdmin); 241 } 242 return true; 243 } 244 245 if (mDevHitCountdown > 0) { 246 mDevHitCountdown--; 247 if (mDevHitCountdown == 0) { 248 getActivity().getSharedPreferences(DevelopmentSettings.PREF_FILE, 249 Context.MODE_PRIVATE).edit().putBoolean( 250 DevelopmentSettings.PREF_SHOW, true).apply(); 251 if (mDevHitToast != null) { 252 mDevHitToast.cancel(); 253 } 254 mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_on, 255 Toast.LENGTH_LONG); 256 mDevHitToast.show(); 257 // This is good time to index the Developer Options 258 Index.getInstance( 259 getActivity().getApplicationContext()).updateFromClassNameResource( 260 DevelopmentSettings.class.getName(), true, true); 261 262 } else if (mDevHitCountdown > 0 263 && mDevHitCountdown < (TAPS_TO_BE_A_DEVELOPER-2)) { 264 if (mDevHitToast != null) { 265 mDevHitToast.cancel(); 266 } 267 mDevHitToast = Toast.makeText(getActivity(), getResources().getQuantityString( 268 R.plurals.show_dev_countdown, mDevHitCountdown, mDevHitCountdown), 269 Toast.LENGTH_SHORT); 270 mDevHitToast.show(); 271 } 272 } else if (mDevHitCountdown < 0) { 273 if (mDevHitToast != null) { 274 mDevHitToast.cancel(); 275 } 276 mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_already, 277 Toast.LENGTH_LONG); 278 mDevHitToast.show(); 279 } 280 } else if (preference.getKey().equals(KEY_SECURITY_PATCH)) { 281 if (getPackageManager().queryIntentActivities(preference.getIntent(), 0).isEmpty()) { 282 // Don't send out the intent to stop crash 283 Log.w(LOG_TAG, "Stop click action on " + KEY_SECURITY_PATCH + ": " 284 + "queryIntentActivities() returns empty" ); 285 return true; 286 } 287 } else if (preference.getKey().equals(KEY_DEVICE_FEEDBACK)) { 288 sendFeedback(); 289 } else if(preference.getKey().equals(KEY_SYSTEM_UPDATE_SETTINGS)) { 290 CarrierConfigManager configManager = 291 (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE); 292 PersistableBundle b = configManager.getConfig(); 293 if (b != null && b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) { 294 ciActionOnSysUpdate(b); 295 } 296 } 297 return super.onPreferenceTreeClick(preference); 298 } 299 300 /** 301 * Trigger client initiated action (send intent) on system update 302 */ 303 private void ciActionOnSysUpdate(PersistableBundle b) { 304 String intentStr = b.getString(CarrierConfigManager. 305 KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING); 306 if (!TextUtils.isEmpty(intentStr)) { 307 String extra = b.getString(CarrierConfigManager. 308 KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING); 309 String extraVal = b.getString(CarrierConfigManager. 310 KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING); 311 312 Intent intent = new Intent(intentStr); 313 if (!TextUtils.isEmpty(extra)) { 314 intent.putExtra(extra, extraVal); 315 } 316 Log.d(LOG_TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr + 317 " with extra " + extra + ", " + extraVal); 318 getActivity().getApplicationContext().sendBroadcast(intent); 319 } 320 } 321 322 private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup, 323 String preference, String property ) { 324 if (SystemProperties.get(property).equals("")) { 325 // Property is missing so remove preference from group 326 try { 327 preferenceGroup.removePreference(findPreference(preference)); 328 } catch (RuntimeException e) { 329 Log.d(LOG_TAG, "Property '" + property + "' missing and no '" 330 + preference + "' preference"); 331 } 332 } 333 } 334 335 private void removePreferenceIfActivityMissing(String preferenceKey, String action) { 336 final Intent intent = new Intent(action); 337 if (getPackageManager().queryIntentActivities(intent, 0).isEmpty()) { 338 Preference pref = findPreference(preferenceKey); 339 if (pref != null) { 340 getPreferenceScreen().removePreference(pref); 341 } 342 } 343 } 344 345 private void removePreferenceIfBoolFalse(String preference, int resId) { 346 if (!getResources().getBoolean(resId)) { 347 Preference pref = findPreference(preference); 348 if (pref != null) { 349 getPreferenceScreen().removePreference(pref); 350 } 351 } 352 } 353 354 private void setStringSummary(String preference, String value) { 355 try { 356 findPreference(preference).setSummary(value); 357 } catch (RuntimeException e) { 358 findPreference(preference).setSummary( 359 getResources().getString(R.string.device_info_default)); 360 } 361 } 362 363 private void setValueSummary(String preference, String property) { 364 try { 365 findPreference(preference).setSummary( 366 SystemProperties.get(property, 367 getResources().getString(R.string.device_info_default))); 368 } catch (RuntimeException e) { 369 // No recovery 370 } 371 } 372 373 private void sendFeedback() { 374 String reporterPackage = DeviceInfoUtils.getFeedbackReporterPackage(getActivity()); 375 if (TextUtils.isEmpty(reporterPackage)) { 376 return; 377 } 378 Intent intent = new Intent(Intent.ACTION_BUG_REPORT); 379 intent.setPackage(reporterPackage); 380 startActivityForResult(intent, 0); 381 } 382 383 private static class SummaryProvider implements SummaryLoader.SummaryProvider { 384 385 private final Context mContext; 386 private final SummaryLoader mSummaryLoader; 387 388 public SummaryProvider(Context context, SummaryLoader summaryLoader) { 389 mContext = context; 390 mSummaryLoader = summaryLoader; 391 } 392 393 @Override 394 public void setListening(boolean listening) { 395 if (listening) { 396 mSummaryLoader.setSummary(this, mContext.getString(R.string.about_summary, 397 Build.VERSION.RELEASE)); 398 } 399 } 400 } 401 402 public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 403 = new SummaryLoader.SummaryProviderFactory() { 404 @Override 405 public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, 406 SummaryLoader summaryLoader) { 407 return new SummaryProvider(activity, summaryLoader); 408 } 409 }; 410 411 /** 412 * For Search. 413 */ 414 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 415 new BaseSearchIndexProvider() { 416 417 @Override 418 public List<SearchIndexableResource> getXmlResourcesToIndex( 419 Context context, boolean enabled) { 420 final SearchIndexableResource sir = new SearchIndexableResource(context); 421 sir.xmlResId = R.xml.device_info_settings; 422 return Arrays.asList(sir); 423 } 424 425 @Override 426 public List<String> getNonIndexableKeys(Context context) { 427 final List<String> keys = new ArrayList<String>(); 428 if (isPropertyMissing(PROPERTY_SELINUX_STATUS)) { 429 keys.add(KEY_SELINUX_STATUS); 430 } 431 if (isPropertyMissing(PROPERTY_URL_SAFETYLEGAL)) { 432 keys.add(KEY_SAFETY_LEGAL); 433 } 434 if (isPropertyMissing(PROPERTY_EQUIPMENT_ID)) { 435 keys.add(KEY_EQUIPMENT_ID); 436 } 437 // Remove Baseband version if wifi-only device 438 if (Utils.isWifiOnly(context)) { 439 keys.add((KEY_BASEBAND_VERSION)); 440 } 441 // Dont show feedback option if there is no reporter. 442 if (TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(context))) { 443 keys.add(KEY_DEVICE_FEEDBACK); 444 } 445 final UserManager um = UserManager.get(context); 446 // TODO: system update needs to be fixed for non-owner user b/22760654 447 if (!um.isAdminUser()) { 448 keys.add(KEY_SYSTEM_UPDATE_SETTINGS); 449 } 450 if (!context.getResources().getBoolean( 451 R.bool.config_additional_system_update_setting_enable)) { 452 keys.add(KEY_UPDATE_SETTING); 453 } 454 return keys; 455 } 456 457 private boolean isPropertyMissing(String property) { 458 return SystemProperties.get(property).equals(""); 459 } 460 }; 461 462 } 463