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 getMetricsCategory()89 protected int getMetricsCategory() { 90 return MetricsEvent.DEVICEINFO; 91 } 92 93 @Override getHelpResource()94 protected int getHelpResource() { 95 return R.string.help_uri_about; 96 } 97 98 @Override onCreate(Bundle icicle)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 onResume()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 onPreferenceTreeClick(Preference preference)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_DEVICE_FEEDBACK)) { 281 sendFeedback(); 282 } else if(preference.getKey().equals(KEY_SYSTEM_UPDATE_SETTINGS)) { 283 CarrierConfigManager configManager = 284 (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE); 285 PersistableBundle b = configManager.getConfig(); 286 if (b != null && b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) { 287 ciActionOnSysUpdate(b); 288 } 289 } 290 return super.onPreferenceTreeClick(preference); 291 } 292 293 /** 294 * Trigger client initiated action (send intent) on system update 295 */ ciActionOnSysUpdate(PersistableBundle b)296 private void ciActionOnSysUpdate(PersistableBundle b) { 297 String intentStr = b.getString(CarrierConfigManager. 298 KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING); 299 if (!TextUtils.isEmpty(intentStr)) { 300 String extra = b.getString(CarrierConfigManager. 301 KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING); 302 String extraVal = b.getString(CarrierConfigManager. 303 KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING); 304 305 Intent intent = new Intent(intentStr); 306 if (!TextUtils.isEmpty(extra)) { 307 intent.putExtra(extra, extraVal); 308 } 309 Log.d(LOG_TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr + 310 " with extra " + extra + ", " + extraVal); 311 getActivity().getApplicationContext().sendBroadcast(intent); 312 } 313 } 314 removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup, String preference, String property )315 private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup, 316 String preference, String property ) { 317 if (SystemProperties.get(property).equals("")) { 318 // Property is missing so remove preference from group 319 try { 320 preferenceGroup.removePreference(findPreference(preference)); 321 } catch (RuntimeException e) { 322 Log.d(LOG_TAG, "Property '" + property + "' missing and no '" 323 + preference + "' preference"); 324 } 325 } 326 } 327 removePreferenceIfActivityMissing(String preferenceKey, String action)328 private void removePreferenceIfActivityMissing(String preferenceKey, String action) { 329 final Intent intent = new Intent(action); 330 if (getPackageManager().queryIntentActivities(intent, 0).isEmpty()) { 331 Preference pref = findPreference(preferenceKey); 332 if (pref != null) { 333 getPreferenceScreen().removePreference(pref); 334 } 335 } 336 } 337 removePreferenceIfBoolFalse(String preference, int resId)338 private void removePreferenceIfBoolFalse(String preference, int resId) { 339 if (!getResources().getBoolean(resId)) { 340 Preference pref = findPreference(preference); 341 if (pref != null) { 342 getPreferenceScreen().removePreference(pref); 343 } 344 } 345 } 346 setStringSummary(String preference, String value)347 private void setStringSummary(String preference, String value) { 348 try { 349 findPreference(preference).setSummary(value); 350 } catch (RuntimeException e) { 351 findPreference(preference).setSummary( 352 getResources().getString(R.string.device_info_default)); 353 } 354 } 355 setValueSummary(String preference, String property)356 private void setValueSummary(String preference, String property) { 357 try { 358 findPreference(preference).setSummary( 359 SystemProperties.get(property, 360 getResources().getString(R.string.device_info_default))); 361 } catch (RuntimeException e) { 362 // No recovery 363 } 364 } 365 sendFeedback()366 private void sendFeedback() { 367 String reporterPackage = DeviceInfoUtils.getFeedbackReporterPackage(getActivity()); 368 if (TextUtils.isEmpty(reporterPackage)) { 369 return; 370 } 371 Intent intent = new Intent(Intent.ACTION_BUG_REPORT); 372 intent.setPackage(reporterPackage); 373 startActivityForResult(intent, 0); 374 } 375 376 private static class SummaryProvider implements SummaryLoader.SummaryProvider { 377 378 private final Context mContext; 379 private final SummaryLoader mSummaryLoader; 380 SummaryProvider(Context context, SummaryLoader summaryLoader)381 public SummaryProvider(Context context, SummaryLoader summaryLoader) { 382 mContext = context; 383 mSummaryLoader = summaryLoader; 384 } 385 386 @Override setListening(boolean listening)387 public void setListening(boolean listening) { 388 if (listening) { 389 mSummaryLoader.setSummary(this, mContext.getString(R.string.about_summary, 390 Build.VERSION.RELEASE)); 391 } 392 } 393 } 394 395 public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 396 = new SummaryLoader.SummaryProviderFactory() { 397 @Override 398 public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, 399 SummaryLoader summaryLoader) { 400 return new SummaryProvider(activity, summaryLoader); 401 } 402 }; 403 404 /** 405 * For Search. 406 */ 407 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 408 new BaseSearchIndexProvider() { 409 410 @Override 411 public List<SearchIndexableResource> getXmlResourcesToIndex( 412 Context context, boolean enabled) { 413 final SearchIndexableResource sir = new SearchIndexableResource(context); 414 sir.xmlResId = R.xml.device_info_settings; 415 return Arrays.asList(sir); 416 } 417 418 @Override 419 public List<String> getNonIndexableKeys(Context context) { 420 final List<String> keys = new ArrayList<String>(); 421 if (isPropertyMissing(PROPERTY_SELINUX_STATUS)) { 422 keys.add(KEY_SELINUX_STATUS); 423 } 424 if (isPropertyMissing(PROPERTY_URL_SAFETYLEGAL)) { 425 keys.add(KEY_SAFETY_LEGAL); 426 } 427 if (isPropertyMissing(PROPERTY_EQUIPMENT_ID)) { 428 keys.add(KEY_EQUIPMENT_ID); 429 } 430 // Remove Baseband version if wifi-only device 431 if (Utils.isWifiOnly(context)) { 432 keys.add((KEY_BASEBAND_VERSION)); 433 } 434 // Dont show feedback option if there is no reporter. 435 if (TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(context))) { 436 keys.add(KEY_DEVICE_FEEDBACK); 437 } 438 final UserManager um = UserManager.get(context); 439 // TODO: system update needs to be fixed for non-owner user b/22760654 440 if (!um.isAdminUser()) { 441 keys.add(KEY_SYSTEM_UPDATE_SETTINGS); 442 } 443 if (!context.getResources().getBoolean( 444 R.bool.config_additional_system_update_setting_enable)) { 445 keys.add(KEY_UPDATE_SETTING); 446 } 447 return keys; 448 } 449 450 private boolean isPropertyMissing(String property) { 451 return SystemProperties.get(property).equals(""); 452 } 453 }; 454 455 } 456