Merge change 27058 into eclair

* changes:
  Fix device picker minor bug
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9393057..5225b9b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -249,6 +249,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="SettingsSafetyLegalActivity"
+                android:label="@string/settings_safetylegal_activity_title"
+                android:theme="@*android:style/Theme.Dialog.Alert">
+            <intent-filter>
+                <action android:name="android.settings.SAFETY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="ApplicationSettings" android:label="@string/applications_settings_header"
                 >
             <intent-filter>
@@ -304,13 +313,20 @@
                 <action android:name="android.settings.SECURITY_SETTINGS" />
                 <action android:name="android.settings.LOCATION_SOURCE_SETTINGS" />
                 <action android:name="android.credentials.UNLOCK" />
-                <action android:name="android.credentials.SYSTEM_INSTALL" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.VOICE_LAUNCH" />
                 <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
         </activity>
 
+        <activity android:name="CredentialInstaller"
+                android:label="@string/credential_installer_activity_title">
+            <intent-filter>
+                <action android:name="android.credentials.SYSTEM_INSTALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="PrivacySettings"
                 android:label="@string/privacy_settings_title"
                 android:configChanges="orientation|keyboardHidden"
diff --git a/res/drawable-hdpi/ic_settings_privacy.png b/res/drawable-hdpi/ic_settings_privacy.png
new file mode 100644
index 0000000..5fb60c2
--- /dev/null
+++ b/res/drawable-hdpi/ic_settings_privacy.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_settings_privacy.png b/res/drawable-mdpi/ic_settings_privacy.png
new file mode 100644
index 0000000..30ba317
--- /dev/null
+++ b/res/drawable-mdpi/ic_settings_privacy.png
Binary files differ
diff --git a/res/layout/battery_info.xml b/res/layout/battery_info.xml
index 62f5d69..1016ad1 100644
--- a/res/layout/battery_info.xml
+++ b/res/layout/battery_info.xml
@@ -26,6 +26,12 @@
         <TextView android:id="@+id/status" style="@style/info_value" />
     </LinearLayout>
 
+    <!-- Battery Status -->
+    <LinearLayout style="@style/entry_layout">
+        <TextView android:text="@string/battery_info_power_label" style="@style/info_label" />
+        <TextView android:id="@+id/power" style="@style/info_value" />
+    </LinearLayout>
+
     <!-- Battery Level -->
     <LinearLayout style="@style/entry_layout">
         <TextView android:text="@string/battery_info_level_label" style="@style/info_label" />
diff --git a/res/layout/compute_sizes.xml b/res/layout/compute_sizes.xml
index 1c8e966..b32ba58 100755
--- a/res/layout/compute_sizes.xml
+++ b/res/layout/compute_sizes.xml
@@ -23,7 +23,7 @@
         android:drawSelectorOnTop="false"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content" />
-    <TextView android:id="@+id/empty_view"
+    <TextView android:id="@android:id/empty"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:paddingLeft="20dip"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5e4c5b5..23ac7ba 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -117,6 +117,8 @@
     <!-- Battery Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_label">Battery status:</string>
     <!-- Battery Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="battery_info_power_label">Power plug:</string>
+    <!-- Battery Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_scale_label">Battery scale:</string>
     <!-- Battery Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_level_label">Battery level:</string>
@@ -157,6 +159,13 @@
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_full">Full</string>
 
+    <!-- Battery Info screen. Units shown after a value.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="battery_info_power_unplugged">Unplugged</string>
+    <string name="battery_info_power_ac">AC</string>
+    <string name="battery_info_power_usb">USB</string>
+    <string name="battery_info_power_ac_usb">AC+USB</string>
+    <string name="battery_info_power_unknown">Unknown</string>
+    
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_health_unknown">Unknown</string>
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
@@ -874,6 +883,12 @@
     <!-- Sound settings screen, setting option summary text when check box is clear -->
     <string name="sound_effects_enable_summary_off">Play sound when making screen selection</string>
     <!-- Sound settings screen, setting check box label -->
+    <string name="haptic_feedback_enable_title">Haptic feedback</string>
+    <!-- Sound settings screen, setting option summary text when check box is selected -->
+    <string name="haptic_feedback_enable_summary_on">Vibrate when pressing soft keys and on certain UI interactions</string>
+    <!-- Sound settings screen, setting option summary text when check box is clear -->
+    <string name="haptic_feedback_enable_summary_off">Vibrate when pressing soft keys and on certain UI interactions</string>
+    <!-- Sound settings screen, setting check box label -->
     <string name="play_media_notification_sounds_enable_title">SD card notifications</string>
     <!-- Sound settings screen, setting option summary text when check box is selected -->
     <string name="play_media_notification_sounds_enable_summary_on">Play sound for SD card notifications</string>
@@ -1219,6 +1234,15 @@
     <!-- About phone settings screen, Open source license dialog title until license is fully loaded -->
     <string name="settings_license_activity_loading">Loading\u2026</string>
 
+    <!-- About phone settings, Safety Legal information setting option name and title of dialog box holding safety legal info -->
+    <string name="settings_safetylegal_title">Safety information</string>
+    <!-- About phone settings, Safety Legal information setting option name and title of dialog box holding safety legal info -->
+    <string name="settings_safetylegal_activity_title">Safety information</string>
+    <!-- About phone settings screen, Safety legal dialog message when data network is not connected -->
+    <string name="settings_safetylegal_activity_unreachable">Your phone is not connected to a data service. To view this information now, go to %s from any computer connected to the Internet.</string>
+    <!-- About phone settings screen, Safety Legal dialog title until the link is fully loaded -->
+    <string name="settings_safetylegal_activity_loading">Loading\u2026</string>
+
     <!-- Lock Pattern settings -->
     <!-- Security & location settings screen, header -->
     <string name="lock_settings_title">Screen unlock pattern</string>
@@ -1883,6 +1907,9 @@
     <string name="gadget_toggle_wifi">Updating Wi-Fi setting</string>
     <string name="gadget_toggle_bluetooth">Updating Bluetooth setting</string>
 
+    <!-- credential installer title -->
+    <string name="credential_installer_activity_title">Credential installer</string>
+
     <string name="vpn_settings_activity_title">VPN settings</string>
 
     <!-- Title of VPN connect dialog -->
diff --git a/res/xml/device_info_settings.xml b/res/xml/device_info_settings.xml
index 81d33b2..860c2ea 100644
--- a/res/xml/device_info_settings.xml
+++ b/res/xml/device_info_settings.xml
@@ -75,6 +75,12 @@
 
         </PreferenceScreen>
         
+        <PreferenceScreen
+                android:key="safetylegal"
+                android:title="@string/settings_safetylegal_title">
+            <intent android:action="android.settings.SAFETY" />
+        </PreferenceScreen>
+
         <!-- Contributors -->
         <!-- 
         <PreferenceScreen
@@ -120,13 +126,4 @@
                 android:title="@string/build_number"
                 android:summary="@string/device_info_default"/>
 
-        <!-- Factory reset -->
-        <PreferenceScreen 
-            android:title="@string/master_clear_title" 
-            android:summary="@string/master_clear_summary">
-            <intent android:action="android.intent.action.MAIN"
-                android:targetPackage="com.android.settings"
-                android:targetClass="com.android.settings.MasterClear" />
-        </PreferenceScreen>
-
 </PreferenceScreen>
diff --git a/res/xml/sound_and_display_settings.xml b/res/xml/sound_and_display_settings.xml
index 1d5e66a..8544fee 100644
--- a/res/xml/sound_and_display_settings.xml
+++ b/res/xml/sound_and_display_settings.xml
@@ -85,6 +85,14 @@
                 android:defaultValue="true" />
 
         <CheckBoxPreference
+                android:key="haptic_feedback"
+                android:title="@string/haptic_feedback_enable_title"
+                android:summaryOn="@string/haptic_feedback_enable_summary_on"
+                android:summaryOff="@string/haptic_feedback_enable_summary_off"
+                android:dependency="silent"
+                android:defaultValue="true" />
+
+        <CheckBoxPreference
                 android:key="play_media_notification_sounds"
                 android:title="@string/play_media_notification_sounds_enable_title"
                 android:summaryOn="@string/play_media_notification_sounds_enable_summary_on"
diff --git a/src/com/android/settings/BatteryInfo.java b/src/com/android/settings/BatteryInfo.java
index 4c25570..1cbe47f 100644
--- a/src/com/android/settings/BatteryInfo.java
+++ b/src/com/android/settings/BatteryInfo.java
@@ -36,6 +36,7 @@
 
 public class BatteryInfo extends Activity {
     private TextView mStatus;
+    private TextView mPower;
     private TextView mLevel;
     private TextView mScale;
     private TextView mHealth;
@@ -111,6 +112,24 @@
                 }
                 mStatus.setText(statusString);
 
+                switch (plugType) {
+                    case 0:
+                        mPower.setText(getString(R.string.battery_info_power_unplugged));
+                        break;
+                    case BatteryManager.BATTERY_PLUGGED_AC:
+                        mPower.setText(getString(R.string.battery_info_power_ac));
+                        break;
+                    case BatteryManager.BATTERY_PLUGGED_USB:
+                        mPower.setText(getString(R.string.battery_info_power_usb));
+                        break;
+                    case (BatteryManager.BATTERY_PLUGGED_AC|BatteryManager.BATTERY_PLUGGED_USB):
+                        mPower.setText(getString(R.string.battery_info_power_ac_usb));
+                        break;
+                    default:
+                        mPower.setText(getString(R.string.battery_info_power_unknown));
+                        break;
+                }
+                
                 int health = intent.getIntExtra("health", BatteryManager.BATTERY_HEALTH_UNKNOWN);
                 String healthString;
                 if (health == BatteryManager.BATTERY_HEALTH_GOOD) {
@@ -148,6 +167,7 @@
         super.onResume();
 
         mStatus = (TextView)findViewById(R.id.status);
+        mPower = (TextView)findViewById(R.id.power);
         mLevel = (TextView)findViewById(R.id.level);
         mScale = (TextView)findViewById(R.id.scale);
         mHealth = (TextView)findViewById(R.id.health);
diff --git a/src/com/android/settings/CredentialInstaller.java b/src/com/android/settings/CredentialInstaller.java
new file mode 100644
index 0000000..5a457d7
--- /dev/null
+++ b/src/com/android/settings/CredentialInstaller.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.util.Log;
+
+/**
+ * Installs credentials to the system keystore. It reacts to the
+ * {@link Credentials#SYSTEM_INSTALL_ACTION} intent. All the key-value pairs in
+ * the intent are installed to the system keystore. For security reason, the
+ * current implementation limits that only com.android.certinstaller can use
+ * this service.
+ */
+public class CredentialInstaller extends Activity {
+    private static final String TAG = "CredentialInstaller";
+
+    private KeyStore mKeyStore = KeyStore.getInstance();
+    private boolean mUnlocking = false;
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        if (!"com.android.certinstaller".equals(getCallingPackage())) finish();
+
+        if (!isKeyStoreLocked()) {
+            install();
+            finish();
+        } else if (!mUnlocking) {
+            mUnlocking = true;
+            Credentials.getInstance().unlock(this);
+        } else {
+            finish();
+        }
+    }
+
+    private void install() {
+        Intent intent = getIntent();
+        Bundle bundle = (intent == null) ? null : intent.getExtras();
+        if (bundle == null) return;
+        for (String key : bundle.keySet()) {
+            byte[] data = bundle.getByteArray(key);
+            if (data == null) continue;
+            boolean success = mKeyStore.put(key.getBytes(), data);
+            Log.v(TAG, "install " + key + ": " + data.length + "  success? " + success);
+            if (!success) return;
+        }
+        setResult(RESULT_OK);
+    }
+
+    private boolean isKeyStoreLocked() {
+        return (mKeyStore.test() != KeyStore.NO_ERROR);
+    }
+}
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index 7768b7d..82b7f28 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -48,6 +48,7 @@
     private static final String KEY_LICENSE = "license";
     private static final String KEY_COPYRIGHT = "copyright";
     private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
+    private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal";
     
     @Override
     protected void onCreate(Bundle icicle) {
@@ -61,6 +62,10 @@
         setStringSummary("build_number", Build.DISPLAY);
         findPreference("kernel_version").setSummary(getFormattedKernelVersion());
 
+        // Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set
+        removePreferenceIfPropertyMissing(getPreferenceScreen(), "safetylegal",
+                PROPERTY_URL_SAFETYLEGAL);
+
         /*
          * Settings is a generic app and should not contain any device-specific
          * info.
@@ -85,7 +90,21 @@
         Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_CONTRIBUTORS,
                 Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
     }
-    
+
+    private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup,
+            String preference, String property ) {
+        if (SystemProperties.get(property).equals(""))
+        {
+            // Property is missing so remove preference from group
+            try {
+                preferenceGroup.removePreference(findPreference(preference));
+            } catch (RuntimeException e) {
+                Log.d(TAG, "Property '" + property + "' missing and no '"
+                        + preference + "' preference");
+            }
+        }
+    }
+
     private void setStringSummary(String preference, String value) {
         try {
             findPreference(preference).setSummary(value);
diff --git a/src/com/android/settings/ManageApplications.java b/src/com/android/settings/ManageApplications.java
index 3d03666..a71d17b 100644
--- a/src/com/android/settings/ManageApplications.java
+++ b/src/com/android/settings/ManageApplications.java
@@ -134,13 +134,13 @@
     // sort order that can be changed through the menu can be sorted alphabetically
     // or size(descending)
     private static final int MENU_OPTIONS_BASE = 0;
-    public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 0;
-    public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 1;
     // Filter options used for displayed list of applications
-    public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 2;
-    public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 3;
-    public static final int FILTER_APPS_RUNNING = MENU_OPTIONS_BASE + 4;
-    public static final int FILTER_OPTIONS = MENU_OPTIONS_BASE + 5;
+    public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 0;
+    public static final int FILTER_APPS_RUNNING = MENU_OPTIONS_BASE + 1;
+    public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 2;
+    public static final int FILTER_OPTIONS = MENU_OPTIONS_BASE + 3;
+    public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 4;
+    public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 5;
     // Alert Dialog presented to user to find out the filter option
     private AlertDialog mAlertDlg;
     // sort order
@@ -212,9 +212,6 @@
     // Cache application attributes
     private AppInfoCache mCache = new AppInfoCache();
     
-    // empty message displayed when list is empty
-    private TextView mEmptyView;
-    
     // Boolean variables indicating state
     private boolean mLoadLabels = false;
     private boolean mSizesFirst = false;
@@ -776,17 +773,6 @@
         }
     }
     
-    private void showEmptyViewIfListEmpty() {
-        if (localLOGV) Log.i(TAG, "Checking for empty view");
-        if (mAppInfoAdapter.getCount() > 0) {
-            mListView.setVisibility(View.VISIBLE);
-            mEmptyView.setVisibility(View.GONE);
-        } else {
-            mListView.setVisibility(View.GONE);
-            mEmptyView.setVisibility(View.VISIBLE);
-        }
-    }
-    
     // internal structure used to track added and deleted packages when
     // the activity has focus
     static class AddRemoveInfo {
@@ -1192,7 +1178,6 @@
            } else {
                notifyDataSetChanged();
            }
-           showEmptyViewIfListEmpty();
            return true;
         }
         
@@ -1594,7 +1579,6 @@
         // initialize the inflater
         mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mReceiver = new PackageIntentReceiver();
-        mEmptyView = (TextView) findViewById(R.id.empty_view);
         mObserver = new PkgSizeObserver();
         // Create adapter and list view here
         List<ApplicationInfo> appList = getInstalledApps(mSortOrder);
@@ -1953,6 +1937,8 @@
         if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
             sendMessageToHandler(REORDER_LIST, menuId);
         } else if (menuId == FILTER_OPTIONS) {
+            // Pick up the selection value from the list of added choice items.
+            int selection = mFilterApps - MENU_OPTIONS_BASE;
             if (mAlertDlg == null) {
                 mAlertDlg = new AlertDialog.Builder(this).
                         setTitle(R.string.filter_dlg_title).
@@ -1960,7 +1946,7 @@
                         setSingleChoiceItems(new CharSequence[] {getText(R.string.filter_apps_all),
                                 getText(R.string.filter_apps_running),
                                 getText(R.string.filter_apps_third_party)},
-                                -1, this).
+                                selection, this).
                         create();
             }
             mAlertDlg.show();
@@ -1985,18 +1971,16 @@
         switch (which) {
         // Make sure that values of 0, 1, 2 match options all, running, third_party when
         // created via the AlertDialog.Builder
-        case 0:
-            newOption = FILTER_APPS_ALL;
+        case FILTER_APPS_ALL:
             break;
-        case 1:
-            newOption = FILTER_APPS_RUNNING;
+        case FILTER_APPS_RUNNING:
             break;
-        case 2:
-            newOption = FILTER_APPS_THIRD_PARTY;
+        case FILTER_APPS_THIRD_PARTY:
             break;
         default:
             return;
         }
+        newOption = which;
         mAlertDlg.dismiss();
         sendMessageToHandler(REORDER_LIST, newOption);
     }
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index ac9600d..ce236fd 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -37,6 +37,7 @@
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.NeighboringCellInfo;
+import android.telephony.cdma.CdmaCellLocation;
 import android.telephony.gsm.GsmCellLocation;
 import android.text.format.DateUtils;
 import android.util.Log;
@@ -73,7 +74,7 @@
 
 public class RadioInfo extends Activity {
     private final String TAG = "phone";
-    
+
     private static final int EVENT_PHONE_STATE_CHANGED = 100;
     private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 200;
     private static final int EVENT_SERVICE_STATE_CHANGED = 300;
@@ -223,7 +224,7 @@
                     ar= (AsyncResult) msg.obj;
                     if (ar.exception == null) {
                         mQxdmLogEnabled = !mQxdmLogEnabled;
-                        
+
                         updateQxdmState(mQxdmLogEnabled);
                         displayQxdmEnableResult();
                     }
@@ -272,7 +273,7 @@
         static final int OEM_QXDM_SDLOG_LEN = 4;
         static final int OEM_PS_AUTO_ATTACH_FUNCTAG = 0x00020000;
         static final int OEM_CIPHERING_FUNCTAG = 0x00020001;
-        
+
         /**
          * The OEM interface to store QXDM to SD.
          *
@@ -343,7 +344,7 @@
         byte[] getCipheringData(boolean enable) {
             return getSimpleFeatureData(OEM_CIPHERING_FUNCTAG, enable);
         }
-        
+
         private byte[] getSimpleFeatureData(int tag, boolean enable) {
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             DataOutputStream dos = new DataOutputStream(bos);
@@ -408,7 +409,7 @@
         preferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
         ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
                 android.R.layout.simple_spinner_item, mPreferredNetworkLabels);
-        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);        
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         preferredNetworkType.setAdapter(adapter);
         preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
 
@@ -428,12 +429,12 @@
         refreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler);
         dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
         dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
-        
+
         mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
         mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED);
         mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED);
         mPhoneStateReceiver.notifyPhoneCallState(EVENT_PHONE_STATE_CHANGED);
-                         
+
         updateQxdmState(null);
         mOem = new OemCommands();
 
@@ -545,7 +546,7 @@
     private boolean isRadioOn() {
         return phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
     }
-    
+
     private void updatePowerState() {
         String buttonText = isRadioOn() ?
                             getString(R.string.turn_off_radio) :
@@ -554,18 +555,18 @@
     }
 
     private void updateQxdmState(Boolean newQxdmStatus) {
-        SharedPreferences sp = 
+        SharedPreferences sp =
           PreferenceManager.getDefaultSharedPreferences(phone.getContext());
         mQxdmLogEnabled = sp.getBoolean("qxdmstatus", false);
         // This is called from onCreate, onResume, and the handler when the status
-        // is updated. 
+        // is updated.
         if (newQxdmStatus != null) {
             SharedPreferences.Editor editor = sp.edit();
             editor.putBoolean("qxdmstatus", newQxdmStatus);
             editor.commit();
             mQxdmLogEnabled = newQxdmStatus;
         }
-        
+
         String buttonText = mQxdmLogEnabled ?
                             getString(R.string.turn_off_qxdm) :
                             getString(R.string.turn_on_qxdm);
@@ -621,38 +622,59 @@
     }
 
     private final void updateLocation(CellLocation location) {
-        int lac = -1;
-        int cid = -1;
+        Resources r = getResources();
         if (location instanceof GsmCellLocation) {
             GsmCellLocation loc = (GsmCellLocation)location;
-            lac = loc.getLac();
-            cid = loc.getCid();
+            int lac = loc.getLac();
+            int cid = loc.getCid();
+            mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
+                    + ((lac == -1) ? "unknown" : Integer.toHexString(lac))
+                    + "   "
+                    + r.getString(R.string.radioInfo_cid) + " = "
+                    + ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
+        } else if (location instanceof CdmaCellLocation) {
+            CdmaCellLocation loc = (CdmaCellLocation)location;
+            int bid = loc.getBaseStationId();
+            int sid = loc.getSystemId();
+            int nid = loc.getNetworkId();
+            int lat = loc.getBaseStationLatitude();
+            int lon = loc.getBaseStationLongitude();
+            mLocation.setText("BID = "
+                    + ((bid == -1) ? "unknown" : Integer.toHexString(bid))
+                    + "   "
+                    + "SID = "
+                    + ((sid == -1) ? "unknown" : Integer.toHexString(sid))
+                    + "   "
+                    + "NID = "
+                    + ((nid == -1) ? "unknown" : Integer.toHexString(nid))
+                    + "\n"
+                    + "LAT = "
+                    + ((lat == -1) ? "unknown" : Integer.toHexString(lat))
+                    + "   "
+                    + "LONG = "
+                    + ((lon == -1) ? "unknown" : Integer.toHexString(lon)));
+        } else {
+            mLocation.setText("unknown");
         }
 
-        Resources r = getResources();
 
-        mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
-                          + ((lac == -1) ? "unknown" : Integer.toHexString(lac))
-                          + "   "
-                          + r.getString(R.string.radioInfo_cid) + " = "
-                + ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
     }
 
     private final void updateNeighboringCids(ArrayList<NeighboringCellInfo> cids) {
-        String neighborings = "";
+        StringBuilder sb = new StringBuilder();
+
         if (cids != null) {
             if ( cids.isEmpty() ) {
-                neighborings = "no neighboring cells";
+                sb.append("no neighboring cells");
             } else {
                 for (NeighboringCellInfo cell : cids) {
-                    neighborings += "{" + Integer.toHexString(cell.getCid()) 
-                    + "@" + cell.getRssi() + "} ";
+                    sb.append(cell.toString()).append(" ");
                 }
             }
         } else {
-            neighborings = "unknown";
+            sb.append("unknown");
         }
-        mNeighboringCids.setText(neighborings);
+        mNeighboringCids.setText(sb.toString());
     }
 
     private final void
@@ -672,7 +694,7 @@
         int state = serviceState.getState();
         Resources r = getResources();
         String display = r.getString(R.string.radioInfo_unknown);
-        
+
         switch (state) {
             case ServiceState.STATE_IN_SERVICE:
                 display = r.getString(R.string.radioInfo_service_in);
@@ -685,9 +707,9 @@
                 display = r.getString(R.string.radioInfo_service_off);
                 break;
         }
-        
+
         gsmState.setText(display);
-        
+
         if (serviceState.getRoaming()) {
             roamingState.setText(R.string.radioInfo_roaming_in);
         } else {
@@ -738,7 +760,7 @@
                 display = r.getString(R.string.radioInfo_data_suspended);
                 break;
         }
-        
+
         gprsState.setText(display);
     }
 
@@ -756,12 +778,12 @@
         Resources r = getResources();
 
         s = phone.getDeviceId();
-        if (s == null) s = r.getString(R.string.radioInfo_unknown); 
+        if (s == null) s = r.getString(R.string.radioInfo_unknown);
         mDeviceId.setText(s);
-        
+
 
         s = phone.getLine1Number();
-        if (s == null) s = r.getString(R.string.radioInfo_unknown); 
+        if (s == null) s = r.getString(R.string.radioInfo_unknown);
         number.setText(s);
     }
 
@@ -792,10 +814,10 @@
             long rxPackets = netstat.getMobileRxPackets();
             long txBytes   = netstat.getMobileTxBytes();
             long rxBytes   = netstat.getMobileRxBytes();
-    
+
             String packets = r.getString(R.string.radioInfo_display_packets);
             String bytes   = r.getString(R.string.radioInfo_display_bytes);
-    
+
             sent.setText(txPackets + " " + packets + ", " + txBytes + " " + bytes);
             received.setText(rxPackets + " " + packets + ", " + rxBytes + " " + bytes);
         } catch (RemoteException e) {
@@ -829,7 +851,7 @@
      */
     private final void pingHostname() {
         try {
-            Process p = Runtime.getRuntime().exec("ping -c 1 www.google.com"); 
+            Process p = Runtime.getRuntime().exec("ping -c 1 www.google.com");
             int status = p.waitFor();
             if (status == 0) {
                 mPingHostnameResult = "Pass";
@@ -1045,7 +1067,7 @@
             return true;
         }
     };
-    
+
     private MenuItem.OnMenuItemClickListener mToggleData = new MenuItem.OnMenuItemClickListener() {
         public boolean onMenuItemClick(MenuItem item) {
             int state = mTelephonyManager.getDataState();
@@ -1091,7 +1113,7 @@
         public void onClick(View v) {
             mCipherOn = !getCiphPref();
             byte[] data = mOem.getCipheringData(mCipherOn);
-            
+
             if (data == null)
                 return;
 
@@ -1100,14 +1122,14 @@
                     mHandler.obtainMessage(EVENT_SET_CIPHER_DONE));
         }
     };
-    
+
     OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
         public void onClick(View v) {
             phone.disableDnsCheck(!phone.isDnsCheckDisabled());
             updateDnsCheckState();
         }
     };
-    
+
     OnClickListener mPingButtonHandler = new OnClickListener() {
         public void onClick(View v) {
             updatePingState();
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index cdfd8bd..80300e0 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -380,9 +380,6 @@
                 mExternalIntent = intent;
                 showCstorDialog(mState == KeyStore.UNINITIALIZED
                         ? CSTOR_INIT_DIALOG : CSTOR_UNLOCK_DIALOG);
-            } else if (Credentials.SYSTEM_INSTALL_ACTION.equals(action)) {
-                mExternalIntent = intent;
-                // TODO: unlock and install.
             }
         }
 
@@ -460,12 +457,7 @@
                 removeDialog(mDialogId);
 
                 if (mExternalIntent != null) {
-                    if (Credentials.SYSTEM_INSTALL_ACTION.equals(
-                                    mExternalIntent.getAction())) {
-                        // TODO: install if unlocked.
-                    } else {
-                        finish();
-                    }
+                    finish();
                 }
             }
         }
diff --git a/src/com/android/settings/SettingsSafetyLegalActivity.java b/src/com/android/settings/SettingsSafetyLegalActivity.java
new file mode 100644
index 0000000..83daa05
--- /dev/null
+++ b/src/com/android/settings/SettingsSafetyLegalActivity.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+
+/**
+ * The "dialog" that shows from "Safety information" in the Settings app.
+ */
+public class SettingsSafetyLegalActivity extends AlertActivity {
+    private static final String PROPERTY_LSAFETYLEGAL_URL = "ro.url.safetylegal";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        String userSafetylegalUrl = SystemProperties.get(PROPERTY_LSAFETYLEGAL_URL);
+
+        final Configuration configuration = getResources().getConfiguration();
+        final String language = configuration.locale.getLanguage();
+        final String country = configuration.locale.getCountry();
+
+        String loc = String.format("locale=%s-%s", language, country);
+
+        userSafetylegalUrl = String.format("%s&%s", userSafetylegalUrl, loc);
+
+        if (!isDataNetworkConnected()) {
+            showErrorAndFinish(userSafetylegalUrl);
+            return;
+        }
+
+        WebView webView = new WebView(this);
+
+        // Begin accessing
+        webView.getSettings().setJavaScriptEnabled(true);
+        webView.loadUrl(userSafetylegalUrl);
+        webView.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                // Change from 'Loading...' to the real title
+                mAlert.setTitle(getString(R.string.settings_safetylegal_activity_title));
+            }
+        });
+
+        final AlertController.AlertParams p = mAlertParams;
+        p.mTitle = getString(R.string.settings_safetylegal_activity_loading);
+        p.mView = webView;
+        p.mForceInverseBackground = true;
+        setupAlert();
+    }
+
+    private void showErrorAndFinish(String url) {
+        new AlertDialog.Builder(this)
+                .setMessage(getResources()
+                        .getString(R.string.settings_safetylegal_activity_unreachable, url))
+                .setTitle(R.string.settings_safetylegal_activity_title)
+                .setPositiveButton(android.R.string.ok, mOkListener)
+                .setCancelable(true)
+                .show();
+    }
+
+    private boolean isDataNetworkConnected() {
+        TelephonyManager mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
+
+        if (mTelephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private final OnClickListener mOkListener = new OnClickListener() {
+         public void onClick(DialogInterface dialog, int whichButton) {
+             finish();
+         }
+    };
+}
diff --git a/src/com/android/settings/SoundAndDisplaySettings.java b/src/com/android/settings/SoundAndDisplaySettings.java
index 75090ee..92297de 100644
--- a/src/com/android/settings/SoundAndDisplaySettings.java
+++ b/src/com/android/settings/SoundAndDisplaySettings.java
@@ -52,6 +52,7 @@
     private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
     private static final String KEY_DTMF_TONE = "dtmf_tone";
     private static final String KEY_SOUND_EFFECTS = "sound_effects";
+    private static final String KEY_HAPTIC_FEEDBACK = "haptic_feedback";
     private static final String KEY_ANIMATIONS = "animations";
     private static final String KEY_ACCELEROMETER = "accelerometer";
     private static final String KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS = "play_media_notification_sounds";
@@ -73,6 +74,7 @@
     private CheckBoxPreference mVibrate;
     private CheckBoxPreference mDtmfTone;
     private CheckBoxPreference mSoundEffects;
+    private CheckBoxPreference mHapticFeedback;
     private ListPreference mAnimations;
     private CheckBoxPreference mAccelerometer;
     private float[] mAnimationScales;
@@ -118,6 +120,10 @@
         mSoundEffects.setPersistent(false);
         mSoundEffects.setChecked(Settings.System.getInt(resolver,
                 Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0);
+        mHapticFeedback = (CheckBoxPreference) findPreference(KEY_HAPTIC_FEEDBACK);
+        mHapticFeedback.setPersistent(false);
+        mHapticFeedback.setChecked(Settings.System.getInt(resolver,
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0);
         mAnimations = (ListPreference) findPreference(KEY_ANIMATIONS);
         mAnimations.setOnPreferenceChangeListener(this);
         mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
@@ -264,6 +270,10 @@
             }
             Settings.System.putInt(getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED,
                     mSoundEffects.isChecked() ? 1 : 0);
+
+        } else if (preference == mHapticFeedback) {
+            Settings.System.putInt(getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED,
+                    mHapticFeedback.isChecked() ? 1 : 0);
             
         } else if (preference == mAccelerometer) {
             Settings.System.putInt(getContentResolver(),
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index 3189810..2e7734b 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -99,7 +99,7 @@
         // Don't update UI to opposite state until we're sure
         return false;
     }
-    
+
     private void setEnabled(final boolean enable) {
         // Disable preference
         mCheckBoxPreference.setEnabled(false);
@@ -115,8 +115,16 @@
             mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_OFF ?
                                            mOriginalSummary :
                                            null);
-            
-            mCheckBoxPreference.setEnabled(isEnabledByDependency());
+
+            /*
+             * Don't ever disable the preference. Only enable here. Disablement
+             * is taken care of by the dependency code. If this is disabled
+             * here, it may not be re-enabled from the framework when dependency
+             * is met. http://b/issue?id=2053751
+             */
+            if (isEnabledByDependency()) {
+                mCheckBoxPreference.setEnabled(true);
+            }
             
         } else if (state == BluetoothAdapter.STATE_TURNING_ON ||
                 state == BluetoothAdapter.STATE_TURNING_OFF) {
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
index e70f85f..0582aa1 100644
--- a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@@ -610,13 +610,22 @@
             return R.drawable.ic_bt_cellphone;
         }
 
-        if (mProfiles.contains(Profile.A2DP)) {
-            return R.drawable.ic_bt_headphones_a2dp;
-        } else if (mProfiles.contains(Profile.HEADSET)) {
-            return R.drawable.ic_bt_headset_hfp;
+        if (mProfiles.size() > 0) {
+            if (mProfiles.contains(Profile.A2DP)) {
+                return R.drawable.ic_bt_headphones_a2dp;
+            } else if (mProfiles.contains(Profile.HEADSET)) {
+                return R.drawable.ic_bt_headset_hfp;
+            }
         } else {
-            return 0;
+            if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
+                return R.drawable.ic_bt_headphones_a2dp;
+
+            }
+            if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+                return R.drawable.ic_bt_headset_hfp;
+            }
         }
+        return 0;
     }
 
     /**
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
index ab77b05..37896bf 100644
--- a/src/com/android/settings/widget/SettingsAppWidgetProvider.java
+++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
@@ -390,8 +390,14 @@
                 }
                 power.setBacklightBrightness(brightness);
                 Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
-                brightness = Settings.System.getInt(cr,
-                        Settings.System.SCREEN_BRIGHTNESS);
+                if (context.getResources().getBoolean(
+                        com.android.internal.R.bool.config_automatic_brightness_available)) {
+                    // Disable automatic brightness
+                    power.setAutoBrightness(false);
+                    Settings.System.putInt(context.getContentResolver(),
+                            Settings.System.SCREEN_BRIGHTNESS_MODE,
+                            0);
+                }
             }
         } catch (RemoteException e) {
             Log.d(TAG, "toggleBrightness: " + e);