OSDN Git Service

Settings: Hidden option to view Device ID
[android-x86/packages-apps-Settings.git] / src / com / android / settings / DeviceInfoSettings.java
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.ClipData;
21 import android.content.ClipboardManager;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.PackageManager.NameNotFoundException;
28 import android.content.pm.ResolveInfo;
29 import android.os.Build;
30 import android.os.Bundle;
31 import android.os.PersistableBundle;
32 import android.os.SELinux;
33 import android.os.SystemClock;
34 import android.os.SystemProperties;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 import android.preference.Preference;
38 import android.preference.PreferenceGroup;
39 import android.preference.PreferenceScreen;
40 import android.provider.SearchIndexableResource;
41 import android.provider.Settings;
42 import android.telephony.CarrierConfigManager;
43 import android.text.TextUtils;
44 import android.text.format.DateFormat;
45 import android.util.Log;
46 import android.widget.Toast;
47
48 import cyanogenmod.hardware.CMHardwareManager;
49 import com.android.internal.logging.MetricsLogger;
50 import com.android.settings.search.BaseSearchIndexProvider;
51 import com.android.settings.search.Index;
52 import com.android.settings.search.Indexable;
53
54 import java.io.BufferedReader;
55 import java.io.FileReader;
56 import java.io.IOException;
57 import java.text.ParseException;
58 import java.text.SimpleDateFormat;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Date;
62 import java.util.List;
63 import java.util.Locale;
64 import java.util.regex.Matcher;
65 import java.util.regex.Pattern;
66
67 public class DeviceInfoSettings extends SettingsPreferenceFragment implements Indexable {
68
69     private static final String LOG_TAG = "DeviceInfoSettings";
70     private static final String FILENAME_PROC_VERSION = "/proc/version";
71     private static final String FILENAME_MSV = "/sys/board_properties/soc/msv";
72
73     private static final String KEY_MANUAL = "manual";
74     private static final String KEY_REGULATORY_INFO = "regulatory_info";
75     private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
76     private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal";
77     private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux";
78     private static final String KEY_KERNEL_VERSION = "kernel_version";
79     private static final String KEY_BUILD_NUMBER = "build_number";
80     private static final String KEY_DEVICE_MODEL = "device_model";
81     private static final String KEY_DEVICE_NAME = "device_name";
82     private static final String KEY_SELINUX_STATUS = "selinux_status";
83     private static final String KEY_BASEBAND_VERSION = "baseband_version";
84     private static final String KEY_FIRMWARE_VERSION = "firmware_version";
85     private static final String KEY_SECURITY_PATCH = "security_patch";
86     private static final String KEY_UPDATE_SETTING = "additional_system_update_settings";
87     private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id";
88     private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid";
89     private static final String KEY_DEVICE_FEEDBACK = "device_feedback";
90     private static final String KEY_SAFETY_LEGAL = "safetylegal";
91     private static final String KEY_MOD_VERSION = "mod_version";
92     private static final String KEY_MOD_BUILD_DATE = "build_date";
93     private static final String KEY_MOD_API_LEVEL = "mod_api_level";
94     private static final String KEY_CM_UPDATES = "cm_updates";
95
96     static final int TAPS_TO_BE_A_DEVELOPER = 7;
97     static final int TAPS_TO_SHOW_DEVICEID = 7;
98
99     long[] mHits = new long[3];
100     int mDevHitCountdown;
101     int mDevIdCountdown;
102     Toast mDevHitToast;
103     Toast mDevIdToast;
104
105     @Override
106     protected int getMetricsCategory() {
107         return MetricsLogger.DEVICEINFO;
108     }
109
110     @Override
111     protected int getHelpResource() {
112         return R.string.help_uri_about;
113     }
114
115     @Override
116     public void onCreate(Bundle icicle) {
117         super.onCreate(icicle);
118
119         addPreferencesFromResource(R.xml.device_info_settings);
120
121         setStringSummary(KEY_FIRMWARE_VERSION, Build.VERSION.RELEASE);
122         findPreference(KEY_FIRMWARE_VERSION).setEnabled(true);
123         String patch = Build.VERSION.SECURITY_PATCH;
124         if (!"".equals(patch)) {
125             try {
126                 SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd");
127                 Date patchDate = template.parse(patch);
128                 String format = DateFormat.getBestDateTimePattern(Locale.getDefault(), "dMMMMyyyy");
129                 patch = DateFormat.format(format, patchDate).toString();
130             } catch (ParseException e) {
131                 // broken parse; fall through and use the raw string
132             }
133             setStringSummary(KEY_SECURITY_PATCH, patch);
134         } else {
135             getPreferenceScreen().removePreference(findPreference(KEY_SECURITY_PATCH));
136
137         }
138         setValueSummary(KEY_BASEBAND_VERSION, "gsm.version.baseband");
139         setValueSummary(KEY_EQUIPMENT_ID, PROPERTY_EQUIPMENT_ID);
140         setStringSummary(KEY_DEVICE_MODEL, Build.MODEL);
141         setStringSummary(KEY_BUILD_NUMBER, Build.DISPLAY);
142         findPreference(KEY_BUILD_NUMBER).setEnabled(true);
143
144         final Preference kernelPref = findPreference(KEY_KERNEL_VERSION);
145         kernelPref.setEnabled(true);
146         kernelPref.setSummary(getFormattedKernelVersion());
147         findPreference(KEY_MOD_VERSION).setSummary(
148                 cyanogenmod.os.Build.CYANOGENMOD_DISPLAY_VERSION);
149         findPreference(KEY_MOD_VERSION).setEnabled(true);
150         setValueSummary(KEY_MOD_BUILD_DATE, "ro.build.date");
151         setExplicitValueSummary(KEY_MOD_API_LEVEL, constructApiLevelString());
152         findPreference(KEY_MOD_API_LEVEL).setEnabled(true);
153         findPreference(KEY_MOD_BUILD_DATE).setEnabled(true);
154
155         if (!SELinux.isSELinuxEnabled()) {
156             String status = getResources().getString(R.string.selinux_status_disabled);
157             setStringSummary(KEY_SELINUX_STATUS, status);
158         } else if (!SELinux.isSELinuxEnforced()) {
159             String status = getResources().getString(R.string.selinux_status_permissive);
160             setStringSummary(KEY_SELINUX_STATUS, status);
161         }
162
163         setStringSummary(KEY_DEVICE_NAME, Build.PRODUCT);
164         removePreferenceIfBoolFalse(KEY_DEVICE_NAME, R.bool.config_displayDeviceName);
165
166         // Remove selinux information if property is not present
167         removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_SELINUX_STATUS,
168                 PROPERTY_SELINUX_STATUS);
169
170         // Only the owner should see the Updater settings, if it exists
171         if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
172             removePreferenceIfPackageNotInstalled(findPreference(KEY_CM_UPDATES));
173         } else {
174             getPreferenceScreen().removePreference(findPreference(KEY_CM_UPDATES));
175         }
176
177         // Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set
178         removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_SAFETY_LEGAL,
179                 PROPERTY_URL_SAFETYLEGAL);
180
181         // Remove Equipment id preference if FCC ID is not set by RIL
182         removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_EQUIPMENT_ID,
183                 PROPERTY_EQUIPMENT_ID);
184
185         // Remove Baseband version if wifi-only device
186         if (Utils.isWifiOnly(getActivity())) {
187             getPreferenceScreen().removePreference(findPreference(KEY_BASEBAND_VERSION));
188         }
189
190         // Dont show feedback option if there is no reporter.
191         if (TextUtils.isEmpty(getFeedbackReporterPackage(getActivity()))) {
192             getPreferenceScreen().removePreference(findPreference(KEY_DEVICE_FEEDBACK));
193         }
194
195         /*
196          * Settings is a generic app and should not contain any device-specific
197          * info.
198          */
199         final Activity act = getActivity();
200
201         // These are contained by the root preference screen
202         PreferenceGroup parentPreference = getPreferenceScreen();
203         if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
204             Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference,
205                     KEY_SYSTEM_UPDATE_SETTINGS,
206                     Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
207             /* Make sure the activity is provided by who we want... */
208             if (findPreference(KEY_SYSTEM_UPDATE_SETTINGS) != null)
209                 removePreferenceIfPackageNotInstalled(findPreference(KEY_SYSTEM_UPDATE_SETTINGS));
210         } else {
211             // Remove for secondary users
212             removePreference(KEY_SYSTEM_UPDATE_SETTINGS);
213         }
214
215         // Read platform settings for additional system update setting
216         removePreferenceIfBoolFalse(KEY_UPDATE_SETTING,
217                 R.bool.config_additional_system_update_setting_enable);
218
219         // Remove manual entry if none present.
220         removePreferenceIfBoolFalse(KEY_MANUAL, R.bool.config_show_manual);
221
222         // Remove regulatory information if none present
223         final Intent intent = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO);
224         if (getPackageManager().queryIntentActivities(intent, 0).isEmpty()) {
225             Preference pref = findPreference(KEY_REGULATORY_INFO);
226             if (pref != null) {
227                 getPreferenceScreen().removePreference(pref);
228             }
229         }
230     }
231
232     @Override
233     public void onResume() {
234         super.onResume();
235         mDevHitCountdown = getActivity().getSharedPreferences(DevelopmentSettings.PREF_FILE,
236                 Context.MODE_PRIVATE).getBoolean(DevelopmentSettings.PREF_SHOW,
237                         android.os.Build.TYPE.equals("eng")) ? -1 : TAPS_TO_BE_A_DEVELOPER;
238         mDevHitToast = null;
239         mDevIdCountdown = TAPS_TO_SHOW_DEVICEID;
240         mDevIdToast = null;
241     }
242
243     @Override
244     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
245         if (preference.getKey().equals(KEY_FIRMWARE_VERSION)) {
246             System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
247             mHits[mHits.length-1] = SystemClock.uptimeMillis();
248             if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
249                 UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
250                 if (um.hasUserRestriction(UserManager.DISALLOW_FUN)) {
251                     Log.d(LOG_TAG, "Sorry, no fun for you!");
252                     return false;
253                 }
254
255                 Intent intent = new Intent(Intent.ACTION_MAIN);
256                 intent.setClassName("android",
257                         com.android.internal.app.PlatLogoActivity.class.getName());
258                 try {
259                     startActivity(intent);
260                 } catch (Exception e) {
261                     Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
262                 }
263             }
264         } else if (preference.getKey().equals(KEY_MOD_BUILD_DATE)) {
265             System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
266             mHits[mHits.length-1] = SystemClock.uptimeMillis();
267             if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
268                 Intent intent = new Intent();
269                 intent.setClassName("com.android.systemui",
270                         "com.android.systemui.tuner.TunerActivity$DemoModeActivity");
271                 try {
272                     startActivity(intent);
273                 } catch (Exception e) {
274                     Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
275                 }
276             }
277         } else if (preference.getKey().equals(KEY_KERNEL_VERSION)) {
278
279             mDevIdCountdown --;
280             if (mDevIdCountdown == 0) {
281                 final CMHardwareManager hwMgr = CMHardwareManager.getInstance(getActivity().getApplicationContext());
282                 final String deviceID = hwMgr.getUniqueDeviceId();
283                 CharSequence msg;
284                 if (deviceID == null) {
285                     msg = getText(R.string.show_device_id_failed_cm);
286                 }
287                 else {
288                     final ClipboardManager clipboardMgr = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
289                     clipboardMgr.setPrimaryClip(ClipData.newPlainText(getResources().
290                                     getString(R.string.show_device_id_clipboard_label),
291                             deviceID));
292                     msg = getResources().getString(
293                             R.string.show_device_id_copied_cm, deviceID);
294                 }
295
296                 mDevIdToast = Toast.makeText(getActivity(), msg,
297                         Toast.LENGTH_LONG);
298                 mDevIdToast.show();
299                 mDevIdCountdown = TAPS_TO_SHOW_DEVICEID;
300             }
301             else if (mDevIdCountdown > 0
302                     && mDevIdCountdown < (TAPS_TO_SHOW_DEVICEID-2)) {
303
304                 if (mDevIdToast != null) {
305                     mDevIdToast.cancel();
306                 }
307                 mDevIdToast = Toast.makeText(getActivity(), getResources().getQuantityString(
308                         R.plurals.show_device_id_countdown_cm, mDevIdCountdown, mDevIdCountdown),
309                         Toast.LENGTH_SHORT);
310                 mDevIdToast.show();
311             }
312
313         } else if (preference.getKey().equals(KEY_BUILD_NUMBER)) {
314             // Don't enable developer options for secondary users.
315             if (UserHandle.myUserId() != UserHandle.USER_OWNER) return true;
316
317             // Don't enable developer options until device has been provisioned
318             if (Settings.Global.getInt(getActivity().getContentResolver(),
319                     Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
320                 return true;
321             }
322
323             final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
324             if (um.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)) return true;
325
326             if (mDevHitCountdown > 0) {
327                 mDevHitCountdown--;
328                 if (mDevHitCountdown == 0) {
329                     getActivity().getSharedPreferences(DevelopmentSettings.PREF_FILE,
330                             Context.MODE_PRIVATE).edit().putBoolean(
331                                     DevelopmentSettings.PREF_SHOW, true).apply();
332                     if (mDevHitToast != null) {
333                         mDevHitToast.cancel();
334                     }
335                     mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_on_cm,
336                             Toast.LENGTH_LONG);
337                     mDevHitToast.show();
338                     // This is good time to index the Developer Options
339                     Index.getInstance(
340                             getActivity().getApplicationContext()).updateFromClassNameResource(
341                                     DevelopmentSettings.class.getName(), true, true);
342
343                 } else if (mDevHitCountdown > 0
344                         && mDevHitCountdown < (TAPS_TO_BE_A_DEVELOPER-2)) {
345                     if (mDevHitToast != null) {
346                         mDevHitToast.cancel();
347                     }
348                     mDevHitToast = Toast.makeText(getActivity(), getResources().getQuantityString(
349                             R.plurals.show_dev_countdown_cm, mDevHitCountdown, mDevHitCountdown),
350                             Toast.LENGTH_SHORT);
351                     mDevHitToast.show();
352                 }
353             } else if (mDevHitCountdown < 0) {
354                 if (mDevHitToast != null) {
355                     mDevHitToast.cancel();
356                 }
357                 mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_already_cm,
358                         Toast.LENGTH_LONG);
359                 mDevHitToast.show();
360             }
361         } else if (preference.getKey().equals(KEY_DEVICE_FEEDBACK)) {
362             sendFeedback();
363         } else if(preference.getKey().equals(KEY_SYSTEM_UPDATE_SETTINGS)) {
364             CarrierConfigManager configManager =
365                     (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE);
366             PersistableBundle b = configManager.getConfig();
367             if (b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
368                 ciActionOnSysUpdate(b);
369             }
370         } else if (preference.getKey().equals(KEY_MOD_VERSION)) {
371             System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
372             mHits[mHits.length-1] = SystemClock.uptimeMillis();
373             if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
374                 Intent intent = new Intent(Intent.ACTION_MAIN);
375                 intent.putExtra("is_cm", true);
376                 intent.setClassName("android",
377                         com.android.internal.app.PlatLogoActivity.class.getName());
378                 try {
379                     startActivity(intent);
380                 } catch (Exception e) {
381                     Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
382                 }
383             }
384         }
385         return super.onPreferenceTreeClick(preferenceScreen, preference);
386     }
387
388     /**
389      * Trigger client initiated action (send intent) on system update
390      */
391     private void ciActionOnSysUpdate(PersistableBundle b) {
392         String intentStr = b.getString(CarrierConfigManager.
393                 KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING);
394         if (!TextUtils.isEmpty(intentStr)) {
395             String extra = b.getString(CarrierConfigManager.
396                     KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING);
397             String extraVal = b.getString(CarrierConfigManager.
398                     KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING);
399
400             Intent intent = new Intent(intentStr);
401             if (!TextUtils.isEmpty(extra)) {
402                 intent.putExtra(extra, extraVal);
403             }
404             Log.d(LOG_TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr +
405                     " with extra " + extra + ", " + extraVal);
406             getActivity().getApplicationContext().sendBroadcast(intent);
407         }
408     }
409
410     private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup,
411             String preference, String property ) {
412         if (SystemProperties.get(property).equals("")) {
413             // Property is missing so remove preference from group
414             try {
415                 preferenceGroup.removePreference(findPreference(preference));
416             } catch (RuntimeException e) {
417                 Log.d(LOG_TAG, "Property '" + property + "' missing and no '"
418                         + preference + "' preference");
419             }
420         }
421     }
422
423     private void removePreferenceIfBoolFalse(String preference, int resId) {
424         if (!getResources().getBoolean(resId)) {
425             Preference pref = findPreference(preference);
426             if (pref != null) {
427                 getPreferenceScreen().removePreference(pref);
428             }
429         }
430     }
431
432     private void setStringSummary(String preference, String value) {
433         try {
434             findPreference(preference).setSummary(value);
435         } catch (RuntimeException e) {
436             findPreference(preference).setSummary(
437                 getResources().getString(R.string.device_info_default));
438         }
439     }
440
441     private void setValueSummary(String preference, String property) {
442         try {
443             findPreference(preference).setSummary(
444                     SystemProperties.get(property,
445                             getResources().getString(R.string.device_info_default)));
446         } catch (RuntimeException e) {
447             // No recovery
448         }
449     }
450
451     private void setExplicitValueSummary(String preference, String value) {
452         try {
453             findPreference(preference).setSummary(value);
454         } catch (RuntimeException e) {
455             // No recovery
456         }
457     }
458
459     private void sendFeedback() {
460         String reporterPackage = getFeedbackReporterPackage(getActivity());
461         if (TextUtils.isEmpty(reporterPackage)) {
462             return;
463         }
464         Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
465         intent.setPackage(reporterPackage);
466         startActivityForResult(intent, 0);
467     }
468
469     /**
470      * Reads a line from the specified file.
471      * @param filename the file to read from
472      * @return the first line, if any.
473      * @throws IOException if the file couldn't be read
474      */
475     private static String readLine(String filename) throws IOException {
476         BufferedReader reader = new BufferedReader(new FileReader(filename), 256);
477         try {
478             return reader.readLine();
479         } finally {
480             reader.close();
481         }
482     }
483
484     public static String getFormattedKernelVersion() {
485         try {
486             return formatKernelVersion(readLine(FILENAME_PROC_VERSION));
487
488         } catch (IOException e) {
489             Log.e(LOG_TAG,
490                 "IO Exception when getting kernel version for Device Info screen",
491                 e);
492
493             return "Unavailable";
494         }
495     }
496
497     private static String constructApiLevelString() {
498         int sdkInt = cyanogenmod.os.Build.CM_VERSION.SDK_INT;
499         StringBuilder builder = new StringBuilder();
500         builder.append(cyanogenmod.os.Build.getNameForSDKInt(sdkInt))
501                 .append(" (" + sdkInt + ")");
502         return builder.toString();
503     }
504
505     public static String formatKernelVersion(String rawKernelVersion) {
506         // Example (see tests for more):
507         // Linux version 3.0.31-g6fb96c9 (android-build@xxx.xxx.xxx.xxx.com) \
508         //     (gcc version 4.6.x-xxx 20120106 (prerelease) (GCC) ) #1 SMP PREEMPT \
509         //     Thu Jun 28 11:02:39 PDT 2012
510
511         final String PROC_VERSION_REGEX =
512             "Linux version (\\S+) " + /* group 1: "3.0.31-g6fb96c9" */
513             "\\((\\S+?)\\) " +        /* group 2: "x@y.com" (kernel builder) */
514             "(?:\\(gcc.+? \\)) " +    /* ignore: GCC version information */
515             "(#\\d+) " +              /* group 3: "#1" */
516             "(?:.*?)?" +              /* ignore: optional SMP, PREEMPT, and any CONFIG_FLAGS */
517             "((Sun|Mon|Tue|Wed|Thu|Fri|Sat).+)"; /* group 4: "Thu Jun 28 11:02:39 PDT 2012" */
518
519         Matcher m = Pattern.compile(PROC_VERSION_REGEX).matcher(rawKernelVersion);
520         if (!m.matches()) {
521             Log.e(LOG_TAG, "Regex did not match on /proc/version: " + rawKernelVersion);
522             return "Unavailable";
523         } else if (m.groupCount() < 4) {
524             Log.e(LOG_TAG, "Regex match on /proc/version only returned " + m.groupCount()
525                     + " groups");
526             return "Unavailable";
527         }
528         return m.group(1) + "\n" +                 // 3.0.31-g6fb96c9
529             m.group(2) + " " + m.group(3) + "\n" + // x@y.com #1
530             m.group(4);                            // Thu Jun 28 11:02:39 PDT 2012
531     }
532
533     /**
534      * Returns " (ENGINEERING)" if the msv file has a zero value, else returns "".
535      * @return a string to append to the model number description.
536      */
537     private String getMsvSuffix() {
538         // Production devices should have a non-zero value. If we can't read it, assume it's a
539         // production device so that we don't accidentally show that it's an ENGINEERING device.
540         try {
541             String msv = readLine(FILENAME_MSV);
542             // Parse as a hex number. If it evaluates to a zero, then it's an engineering build.
543             if (Long.parseLong(msv, 16) == 0) {
544                 return " (ENGINEERING)";
545             }
546         } catch (IOException ioe) {
547             // Fail quietly, as the file may not exist on some devices.
548         } catch (NumberFormatException nfe) {
549             // Fail quietly, returning empty string should be sufficient
550         }
551         return "";
552     }
553
554     private static String getFeedbackReporterPackage(Context context) {
555         final String feedbackReporter =
556                 context.getResources().getString(R.string.oem_preferred_feedback_reporter);
557         if (TextUtils.isEmpty(feedbackReporter)) {
558             // Reporter not configured. Return.
559             return feedbackReporter;
560         }
561         // Additional checks to ensure the reporter is on system image, and reporter is
562         // configured to listen to the intent. Otherwise, dont show the "send feedback" option.
563         final Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
564
565         PackageManager pm = context.getPackageManager();
566         List<ResolveInfo> resolvedPackages =
567                 pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER);
568         for (ResolveInfo info : resolvedPackages) {
569             if (info.activityInfo != null) {
570                 if (!TextUtils.isEmpty(info.activityInfo.packageName)) {
571                     try {
572                         ApplicationInfo ai = pm.getApplicationInfo(info.activityInfo.packageName, 0);
573                         if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
574                             // Package is on the system image
575                             if (TextUtils.equals(
576                                         info.activityInfo.packageName, feedbackReporter)) {
577                                 return feedbackReporter;
578                             }
579                         }
580                     } catch (PackageManager.NameNotFoundException e) {
581                          // No need to do anything here.
582                     }
583                 }
584             }
585         }
586         return null;
587     }
588
589     /**
590      * For Search.
591      */
592     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
593         new BaseSearchIndexProvider() {
594
595             @Override
596             public List<SearchIndexableResource> getXmlResourcesToIndex(
597                     Context context, boolean enabled) {
598                 final SearchIndexableResource sir = new SearchIndexableResource(context);
599                 sir.xmlResId = R.xml.device_info_settings;
600                 return Arrays.asList(sir);
601             }
602
603             @Override
604             public List<String> getNonIndexableKeys(Context context) {
605                 final List<String> keys = new ArrayList<String>();
606                 if (isPropertyMissing(PROPERTY_SELINUX_STATUS)) {
607                     keys.add(KEY_SELINUX_STATUS);
608                 }
609                 if (isPropertyMissing(PROPERTY_URL_SAFETYLEGAL)) {
610                     keys.add(KEY_SAFETY_LEGAL);
611                 }
612                 if (isPropertyMissing(PROPERTY_EQUIPMENT_ID)) {
613                     keys.add(KEY_EQUIPMENT_ID);
614                 }
615                 // Remove Baseband version if wifi-only device
616                 if (Utils.isWifiOnly(context)) {
617                     keys.add((KEY_BASEBAND_VERSION));
618                 }
619                 // Dont show feedback option if there is no reporter.
620                 if (TextUtils.isEmpty(getFeedbackReporterPackage(context))) {
621                     keys.add(KEY_DEVICE_FEEDBACK);
622                 }
623                 if (UserHandle.myUserId() != UserHandle.USER_OWNER) {
624                     keys.add(KEY_SYSTEM_UPDATE_SETTINGS);
625                 }
626                 if (!context.getResources().getBoolean(
627                         R.bool.config_additional_system_update_setting_enable)) {
628                     keys.add(KEY_UPDATE_SETTING);
629                 }
630                 return keys;
631             }
632
633             private boolean isPropertyMissing(String property) {
634                 return SystemProperties.get(property).equals("");
635             }
636         };
637
638     private boolean removePreferenceIfPackageNotInstalled(Preference preference) {
639         String intentUri=((PreferenceScreen) preference).getIntent().toUri(1);
640         Pattern pattern = Pattern.compile("component=([^/]+)/");
641         Matcher matcher = pattern.matcher(intentUri);
642
643         String packageName=matcher.find()?matcher.group(1):null;
644         if(packageName != null) {
645             try {
646                 PackageInfo pi = getPackageManager().getPackageInfo(packageName,
647                         PackageManager.GET_ACTIVITIES);
648                 if (!pi.applicationInfo.enabled) {
649                     Log.e(LOG_TAG,"package "+packageName+" is disabled, hiding preference.");
650                     getPreferenceScreen().removePreference(preference);
651                     return true;
652                 }
653             } catch (NameNotFoundException e) {
654                 Log.e(LOG_TAG,"package "+packageName+" not installed, hiding preference.");
655                 getPreferenceScreen().removePreference(preference);
656                 return true;
657             }
658         }
659         return false;
660     }
661 }
662