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 information if none present. 179 final Intent intent = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO); 180 if (getPackageManager().queryIntentActivities(intent, 0).isEmpty()) { 181 Preference pref = findPreference(KEY_REGULATORY_INFO); 182 if (pref != null) { 183 getPreferenceScreen().removePreference(pref); 184 } 185 } 186 } 187 188 @Override onResume()189 public void onResume() { 190 super.onResume(); 191 mDevHitCountdown = getActivity().getSharedPreferences(DevelopmentSettings.PREF_FILE, 192 Context.MODE_PRIVATE).getBoolean(DevelopmentSettings.PREF_SHOW, 193 android.os.Build.TYPE.equals("eng")) ? -1 : TAPS_TO_BE_A_DEVELOPER; 194 mDevHitToast = null; 195 mFunDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced( 196 getActivity(), UserManager.DISALLOW_FUN, UserHandle.myUserId()); 197 mFunDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( 198 getActivity(), UserManager.DISALLOW_FUN, UserHandle.myUserId()); 199 mDebuggingFeaturesDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced( 200 getActivity(), UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.myUserId()); 201 mDebuggingFeaturesDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( 202 getActivity(), UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.myUserId()); 203 } 204 205 @Override onPreferenceTreeClick(Preference preference)206 public boolean onPreferenceTreeClick(Preference preference) { 207 if (preference.getKey().equals(KEY_FIRMWARE_VERSION)) { 208 System.arraycopy(mHits, 1, mHits, 0, mHits.length-1); 209 mHits[mHits.length-1] = SystemClock.uptimeMillis(); 210 if (mHits[0] >= (SystemClock.uptimeMillis()-500)) { 211 if (mUm.hasUserRestriction(UserManager.DISALLOW_FUN)) { 212 if (mFunDisallowedAdmin != null && !mFunDisallowedBySystem) { 213 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), 214 mFunDisallowedAdmin); 215 } 216 Log.d(LOG_TAG, "Sorry, no fun for you!"); 217 return false; 218 } 219 220 Intent intent = new Intent(Intent.ACTION_MAIN); 221 intent.setClassName("android", 222 com.android.internal.app.PlatLogoActivity.class.getName()); 223 try { 224 startActivity(intent); 225 } catch (Exception e) { 226 Log.e(LOG_TAG, "Unable to start activity " + intent.toString()); 227 } 228 } 229 } else if (preference.getKey().equals(KEY_BUILD_NUMBER)) { 230 // Don't enable developer options for secondary users. 231 if (!mUm.isAdminUser()) return true; 232 233 // Don't enable developer options until device has been provisioned 234 if (!Utils.isDeviceProvisioned(getActivity())) { 235 return true; 236 } 237 238 if (mUm.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)) { 239 if (mDebuggingFeaturesDisallowedAdmin != null && 240 !mDebuggingFeaturesDisallowedBySystem) { 241 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), 242 mDebuggingFeaturesDisallowedAdmin); 243 } 244 return true; 245 } 246 247 if (mDevHitCountdown > 0) { 248 mDevHitCountdown--; 249 if (mDevHitCountdown == 0) { 250 getActivity().getSharedPreferences(DevelopmentSettings.PREF_FILE, 251 Context.MODE_PRIVATE).edit().putBoolean( 252 DevelopmentSettings.PREF_SHOW, true).apply(); 253 if (mDevHitToast != null) { 254 mDevHitToast.cancel(); 255 } 256 mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_on, 257 Toast.LENGTH_LONG); 258 mDevHitToast.show(); 259 // This is good time to index the Developer Options 260 Index.getInstance( 261 getActivity().getApplicationContext()).updateFromClassNameResource( 262 DevelopmentSettings.class.getName(), true, true); 263 264 } else if (mDevHitCountdown > 0 265 && mDevHitCountdown < (TAPS_TO_BE_A_DEVELOPER-2)) { 266 if (mDevHitToast != null) { 267 mDevHitToast.cancel(); 268 } 269 mDevHitToast = Toast.makeText(getActivity(), getResources().getQuantityString( 270 R.plurals.show_dev_countdown, mDevHitCountdown, mDevHitCountdown), 271 Toast.LENGTH_SHORT); 272 mDevHitToast.show(); 273 } 274 } else if (mDevHitCountdown < 0) { 275 if (mDevHitToast != null) { 276 mDevHitToast.cancel(); 277 } 278 mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_already, 279 Toast.LENGTH_LONG); 280 mDevHitToast.show(); 281 } 282 } else if (preference.getKey().equals(KEY_DEVICE_FEEDBACK)) { 283 sendFeedback(); 284 } else if(preference.getKey().equals(KEY_SYSTEM_UPDATE_SETTINGS)) { 285 CarrierConfigManager configManager = 286 (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE); 287 PersistableBundle b = configManager.getConfig(); 288 if (b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) { 289 ciActionOnSysUpdate(b); 290 } 291 } 292 return super.onPreferenceTreeClick(preference); 293 } 294 295 /** 296 * Trigger client initiated action (send intent) on system update 297 */ ciActionOnSysUpdate(PersistableBundle b)298 private void ciActionOnSysUpdate(PersistableBundle b) { 299 String intentStr = b.getString(CarrierConfigManager. 300 KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING); 301 if (!TextUtils.isEmpty(intentStr)) { 302 String extra = b.getString(CarrierConfigManager. 303 KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING); 304 String extraVal = b.getString(CarrierConfigManager. 305 KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING); 306 307 Intent intent = new Intent(intentStr); 308 if (!TextUtils.isEmpty(extra)) { 309 intent.putExtra(extra, extraVal); 310 } 311 Log.d(LOG_TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr + 312 " with extra " + extra + ", " + extraVal); 313 getActivity().getApplicationContext().sendBroadcast(intent); 314 } 315 } 316 removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup, String preference, String property )317 private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup, 318 String preference, String property ) { 319 if (SystemProperties.get(property).equals("")) { 320 // Property is missing so remove preference from group 321 try { 322 preferenceGroup.removePreference(findPreference(preference)); 323 } catch (RuntimeException e) { 324 Log.d(LOG_TAG, "Property '" + property + "' missing and no '" 325 + preference + "' preference"); 326 } 327 } 328 } 329 removePreferenceIfBoolFalse(String preference, int resId)330 private void removePreferenceIfBoolFalse(String preference, int resId) { 331 if (!getResources().getBoolean(resId)) { 332 Preference pref = findPreference(preference); 333 if (pref != null) { 334 getPreferenceScreen().removePreference(pref); 335 } 336 } 337 } 338 setStringSummary(String preference, String value)339 private void setStringSummary(String preference, String value) { 340 try { 341 findPreference(preference).setSummary(value); 342 } catch (RuntimeException e) { 343 findPreference(preference).setSummary( 344 getResources().getString(R.string.device_info_default)); 345 } 346 } 347 setValueSummary(String preference, String property)348 private void setValueSummary(String preference, String property) { 349 try { 350 findPreference(preference).setSummary( 351 SystemProperties.get(property, 352 getResources().getString(R.string.device_info_default))); 353 } catch (RuntimeException e) { 354 // No recovery 355 } 356 } 357 sendFeedback()358 private void sendFeedback() { 359 String reporterPackage = DeviceInfoUtils.getFeedbackReporterPackage(getActivity()); 360 if (TextUtils.isEmpty(reporterPackage)) { 361 return; 362 } 363 Intent intent = new Intent(Intent.ACTION_BUG_REPORT); 364 intent.setPackage(reporterPackage); 365 startActivityForResult(intent, 0); 366 } 367 368 private static class SummaryProvider implements SummaryLoader.SummaryProvider { 369 370 private final Context mContext; 371 private final SummaryLoader mSummaryLoader; 372 SummaryProvider(Context context, SummaryLoader summaryLoader)373 public SummaryProvider(Context context, SummaryLoader summaryLoader) { 374 mContext = context; 375 mSummaryLoader = summaryLoader; 376 } 377 378 @Override setListening(boolean listening)379 public void setListening(boolean listening) { 380 if (listening) { 381 mSummaryLoader.setSummary(this, mContext.getString(R.string.about_summary, 382 Build.VERSION.RELEASE)); 383 } 384 } 385 } 386 387 public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 388 = new SummaryLoader.SummaryProviderFactory() { 389 @Override 390 public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, 391 SummaryLoader summaryLoader) { 392 return new SummaryProvider(activity, summaryLoader); 393 } 394 }; 395 396 /** 397 * For Search. 398 */ 399 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 400 new BaseSearchIndexProvider() { 401 402 @Override 403 public List<SearchIndexableResource> getXmlResourcesToIndex( 404 Context context, boolean enabled) { 405 final SearchIndexableResource sir = new SearchIndexableResource(context); 406 sir.xmlResId = R.xml.device_info_settings; 407 return Arrays.asList(sir); 408 } 409 410 @Override 411 public List<String> getNonIndexableKeys(Context context) { 412 final List<String> keys = new ArrayList<String>(); 413 if (isPropertyMissing(PROPERTY_SELINUX_STATUS)) { 414 keys.add(KEY_SELINUX_STATUS); 415 } 416 if (isPropertyMissing(PROPERTY_URL_SAFETYLEGAL)) { 417 keys.add(KEY_SAFETY_LEGAL); 418 } 419 if (isPropertyMissing(PROPERTY_EQUIPMENT_ID)) { 420 keys.add(KEY_EQUIPMENT_ID); 421 } 422 // Remove Baseband version if wifi-only device 423 if (Utils.isWifiOnly(context)) { 424 keys.add((KEY_BASEBAND_VERSION)); 425 } 426 // Dont show feedback option if there is no reporter. 427 if (TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(context))) { 428 keys.add(KEY_DEVICE_FEEDBACK); 429 } 430 final UserManager um = UserManager.get(context); 431 // TODO: system update needs to be fixed for non-owner user b/22760654 432 if (!um.isAdminUser()) { 433 keys.add(KEY_SYSTEM_UPDATE_SETTINGS); 434 } 435 if (!context.getResources().getBoolean( 436 R.bool.config_additional_system_update_setting_enable)) { 437 keys.add(KEY_UPDATE_SETTING); 438 } 439 return keys; 440 } 441 442 private boolean isPropertyMissing(String property) { 443 return SystemProperties.get(property).equals(""); 444 } 445 }; 446 447 } 448