Use PreferenceActivity and FragmentBreadCrumbs as they offer the same capabilities now.

Also fix: 2997438 and a similar bug in Tether Settings
Show + menu item for User Dictionary
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 287e312..dacc19f 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -106,6 +106,8 @@
     private LockPatternUtils mLockPatternUtils;
     private ListPreference mLockAfter;
     
+    private SettingsObserver mSettingsObserver;
+
     private final class SettingsObserver implements Observer {
         public void update(Observable o, Object arg) {
             updateToggles();
@@ -125,14 +127,24 @@
         createPreferenceHierarchy();
 
         updateToggles();
+    }
 
+    @Override
+    public void onStart() {
+        super.onStart();
         // listen for Location Manager settings changes
         Cursor settingsCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, null,
                 "(" + Settings.System.NAME + "=?)",
                 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
                 null);
         mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null);
-        mContentQueryMap.addObserver(new SettingsObserver());
+        mContentQueryMap.addObserver(mSettingsObserver = new SettingsObserver());
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        mContentQueryMap.deleteObserver(mSettingsObserver);
     }
 
     private PreferenceScreen createPreferenceHierarchy() {
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 224aa53..738acc3 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -16,354 +16,61 @@
 
 package com.android.settings;
 
-import android.app.Activity;
 import android.app.Fragment;
-import android.content.Context;
-import android.content.Intent;
 import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceScreen;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.LinearLayout;
-import android.widget.TextView;
+import android.preference.PreferenceActivity;
 
-import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Top-level settings activity to handle single pane and double pane UI layout.
  */
-public class Settings extends Activity
-        implements PreferenceFragment.OnPreferenceStartFragmentCallback,
-        SettingsPreferenceFragment.OnStateListener,
+public class Settings extends PreferenceActivity implements
         SettingsPreferenceFragment.FragmentStarter {
 
-    private static final boolean DBG = false;
+    // TODO: Update Call Settings based on airplane mode state.
 
-    private static final String TAG = "Settings";
-
-    private static final String KEY_PARENT = "parent";
-    private static final String KEY_CALL_SETTINGS = "call_settings";
-    private static final String KEY_SYNC_SETTINGS = "sync_settings";
-    private static final String KEY_SEARCH_SETTINGS = "search_settings";
-    private static final String KEY_DOCK_SETTINGS = "dock_settings";
-
-    private static final String KEY_OPERATOR_SETTINGS = "operator_settings";
-    private static final String KEY_MANUFACTURER_SETTINGS = "manufacturer_settings";
-
-    public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
-
-    public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
-
-    private static final String BACK_STACK_PREFS = ":settings:prefs";
-
-    private View mPrefsPane;
-    private View mMainPane;
-    private boolean mSinglePane;
-
-    private BreadCrumbs mBreadCrumbs;
-
+    /**
+     * Populate the activity with the top-level headers.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.settings_top_level);
-        mPrefsPane = findViewById(R.id.prefs);
-        mMainPane = findViewById(R.id.top_level);
-        mSinglePane = mMainPane == null;
-        if (mSinglePane) mMainPane = mPrefsPane;
+    public void onBuildHeaders(List<Header> target) {
+        loadHeadersFromResource(R.xml.settings_headers, target);
 
-        final Intent intent = getIntent();
-        String initialFragment = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
-        Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+        updateHeaderList(target);
+    }
 
-        createActionBar();
-
-        if (mSinglePane) {
-            if (initialFragment != null) {
-                showFragment(initialFragment, initialArguments);
-            } else {
-                // Intent#getCompontent() lets us get Fragment name, even when the Intent is
-                // given via <activity-alias>.
-                //
-                // e.g. When we reach here via "ChildSetting" activity-alias,
-                // we should get the name here instead of targetActivity ("Settings").
-                if (intent.getComponent().getClassName().equals(this.getClass().getName())) {
-                    showFragment(TopLevelSettings.class.getName(), null);
-                } else {
-                    showFragment(intent.getComponent().getClassName(), intent.getExtras());
-                }
+    private void updateHeaderList(List<Header> target) {
+        int i = 0;
+        while (i < target.size()) {
+            Header header = target.get(i);
+            long id = header.id;
+            if (id == R.id.dock_settings) {
+                if (!needsDockSettings())
+                    target.remove(header);
+            } else if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
+                Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
+            } else if (id == R.id.call_settings) {
+                if (!Utils.isVoiceCapable(this))
+                    target.remove(header);
             }
-        } else {
-            if (!intent.getComponent().getClassName().equals(this.getClass().getName())) {
-                if (showFragment(intent.getComponent().getClassName(), intent.getExtras())) {
-                    mMainPane.setVisibility(View.GONE);
-                }
-            } else {
-                Fragment topLevel = getFragmentManager().findFragmentById(R.id.top_level);
-                if (topLevel != null) {
-                    ((TopLevelSettings) topLevel).selectFirst();
-                }
-            }
+            if (target.get(i) == header)
+                i++;
         }
     }
 
-    private void createActionBar() {
-        LayoutInflater inflater = (LayoutInflater)
-                getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View customNavBar = inflater.inflate(R.layout.settings_actionbar, null, false);
-        getActionBar().setCustomNavigationMode(customNavBar);
-        mBreadCrumbs = (BreadCrumbs) customNavBar.findViewById(R.id.bread_crumbs);
-        mBreadCrumbs.setActivity(this);
+    private boolean needsDockSettings() {
+        return getResources().getBoolean(R.bool.has_dock_settings);
     }
 
-    boolean showFragment(Preference preference) {
-        if (mSinglePane) {
-            startWithFragment(preference.getFragment(), preference.getExtras());
-            return false;
-        } else {
-            mBreadCrumbs.clear();
-            return showFragment(preference.getFragment(), preference.getExtras());
-        }
-    }
-
-    private void startWithFragment(String fragmentName, Bundle args) {
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClass(this, getClass());
-        intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
-        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
-        startActivity(intent);
-    }
-
-    private boolean showFragment(String fragmentClass, Bundle extras) {
-        if (DBG) Log.d(TAG, "showFragment");
-       Fragment f = Fragment.instantiate(this, fragmentClass, extras);
-        if (f instanceof SettingsPreferenceFragment) {
-            SettingsPreferenceFragment spf = (SettingsPreferenceFragment) f;
-            spf.setOnStateListener(this);
-            spf.setFragmentStarter(this);
-        }
-        mBreadCrumbs.clear();
-        getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
-        getFragmentManager().openTransaction().replace(R.id.prefs, f).commit();
-        return true;
-    }
-
-    private void addToBreadCrumbs(Fragment fragment) {
-        final CharSequence title = ((PreferenceFragment) fragment)
-                .getPreferenceScreen().getTitle();
-        if (mSinglePane) {
-            mBreadCrumbs.clear();
-        }
-        mBreadCrumbs.push(title);
-    }
-
-    private void removeFromBreadCrumbs(Fragment fragment) {
-        mBreadCrumbs.pop(((PreferenceFragment) fragment).getPreferenceScreen().getTitle());
-        mBreadCrumbs.update();
-    }
-
-    public void onCreated(SettingsPreferenceFragment fragment) {
-        if (DBG) Log.d(TAG, "Fragment created " + fragment);
-        addToBreadCrumbs(fragment);
-    }
-
-    public void onDestroyed(SettingsPreferenceFragment fragment) {
-        Log.d(TAG, "Fragment destroyed " + fragment + " (name: " + fragment.getClass() + ")");
-    }
-
-    public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
-        if (DBG) Log.d(TAG, "onPreferenceStartFragment");
-        return startFragment(caller, pref.getFragment(), -1, pref.getExtras());
-    }
-
-    public boolean startFragment(
-            Fragment caller, String fragmentClass, int requestCode, Bundle extras) {
+    public boolean startFragment(Fragment caller, String fragmentClass, int requestCode,
+            Bundle extras) {
         Fragment f = Fragment.instantiate(this, fragmentClass, extras);
         caller.setTargetFragment(f, requestCode);
         if (f instanceof SettingsPreferenceFragment) {
             SettingsPreferenceFragment spf = (SettingsPreferenceFragment) f;
-            spf.setOnStateListener(this);
             spf.setFragmentStarter(this);
         }
-        getFragmentManager().openTransaction().replace(R.id.prefs, f)
-                .addToBackStack(BACK_STACK_PREFS).commit();
         return true;
     }
-
-    @Override
-    public void onBackPressed() {
-        mBreadCrumbs.pop();
-        mBreadCrumbs.update();
-        super.onBackPressed();
-    }
-
-    public static class TopLevelSettings extends PreferenceFragment {
-
-        private IconPreferenceScreen mHighlightedPreference;
-
-        @Override
-        public void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-
-            // Load the preferences from an XML resource
-            addPreferencesFromResource(R.xml.settings);
-
-            updatePreferenceList();
-        }
-
-        @Override
-        public void onResume() {
-            super.onResume();
-
-            updateCallSettings();
-        }
-
-        private void updateCallSettings() {
-            Preference callSettings = findPreference(KEY_CALL_SETTINGS);
-            // Might have been removed in non-voice-capable devices
-            if (callSettings != null) {
-                callSettings.setEnabled(!AirplaneModeEnabler.isAirplaneModeOn(getActivity()));
-            }
-        }
-
-        private void updatePreferenceList() {
-            final Activity activity = getActivity();
-            PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT);
-            Preference dockSettings = parent.findPreference(KEY_DOCK_SETTINGS);
-            if (activity.getResources().getBoolean(R.bool.has_dock_settings) == false
-                    && dockSettings != null) {
-                parent.removePreference(dockSettings);
-            }
-
-            Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(activity, parent,
-                    KEY_OPERATOR_SETTINGS);
-            Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(activity, parent,
-                    KEY_MANUFACTURER_SETTINGS);
-
-            Preference callSettings = parent.findPreference(KEY_CALL_SETTINGS);
-            if (!Utils.isVoiceCapable(activity) && callSettings != null) {
-                parent.removePreference(callSettings);
-            }
-        }
-
-        @Override
-        public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
-            // If it is a fragment preference, replace the prefs pane in the 2 pane UI.
-            final String fragmentClass = preference.getFragment();
-            if (fragmentClass != null) {
-                boolean showed = ((Settings) getActivity()).showFragment(preference);
-                if (showed) {
-                    highlight(preference);
-                }
-                return showed;
-            }
-            return false;
-        }
-
-        void highlight(Preference preference) {
-            if (mHighlightedPreference != null) {
-                mHighlightedPreference.setHighlighted(false);
-            }
-            mHighlightedPreference = (IconPreferenceScreen) preference;
-            mHighlightedPreference.setHighlighted(true);
-        }
-
-        void selectFirst() {
-            Preference first = getPreferenceScreen().getPreference(0);
-            onPreferenceTreeClick(getPreferenceScreen(), first);
-        }
-    }
-
-    public static class BreadCrumbs extends LinearLayout implements OnClickListener {
-
-        private ArrayList<CharSequence> mTitles = new ArrayList<CharSequence>();
-        private TextView mLevelUpTitle;
-        private TextView mCurrentLevelTitle;
-        private View mDivider;
-        private Activity mActivity;
-
-        public BreadCrumbs(Context context) {
-            this(context, null);
-        }
-
-        public BreadCrumbs(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public void push(CharSequence title) {
-            if (mTitles.size() == 0
-                    || !TextUtils.equals(title, mTitles.get(mTitles.size() - 1))) {
-                mTitles.add(title);
-                update();
-            }
-        }
-
-        public void pop() {
-            if (mTitles.size() > 0) {
-                mTitles.remove(mTitles.size() - 1);
-            }
-        }
-
-        public void pop(CharSequence title) {
-            if (mTitles.size() > 1) {
-                mTitles.remove(title);
-            }
-        }
-
-        public void clear() {
-            mTitles.clear();
-        }
-
-        private void initNavViews() {
-            if (mLevelUpTitle == null) {
-                mLevelUpTitle = (TextView) findViewById(R.id.level_up_title);
-                mCurrentLevelTitle = (TextView) findViewById(R.id.level_current_title);
-                mDivider = findViewById(R.id.level_divider);
-                if (mLevelUpTitle != null) {
-                    mLevelUpTitle.setOnClickListener(this);
-                }
-                if (mCurrentLevelTitle != null) {
-                    mCurrentLevelTitle.setOnClickListener(this);
-                }
-            }
-        }
-
-        public void update() {
-            initNavViews();
-            if (mLevelUpTitle == null) return;
-
-            final int titleCount = mTitles.size();
-            if (titleCount > 1) {
-                mLevelUpTitle.setText(mTitles.get(titleCount - 2));
-                mLevelUpTitle.setVisibility(VISIBLE);
-                mDivider.setVisibility(VISIBLE);
-            } else {
-                mLevelUpTitle.setVisibility(GONE);
-                mDivider.setVisibility(GONE);
-            }
-            if (titleCount > 0) {
-                mCurrentLevelTitle.setText(mTitles.get(titleCount - 1));
-            } else {
-                mCurrentLevelTitle.setText("");
-            }
-        }
-
-        public void setActivity(Activity activity) {
-            mActivity = activity;
-        }
-
-        public void onClick(View v) {
-            if (mActivity == null)
-                return;
-            if (v == mLevelUpTitle) {
-                mActivity.onBackPressed();
-            }
-        }
-    }
 }
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index 87726c1..f632a02 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -35,7 +35,6 @@
 import android.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
-import android.util.Log;
 import android.webkit.WebView;
 
 import java.io.InputStream;
@@ -220,8 +219,8 @@
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
+    public void onStart() {
+        super.onStart();
 
         final Activity activity = getActivity();
 
@@ -244,8 +243,8 @@
     }
 
     @Override
-    public void onPause() {
-        super.onPause();
+    public void onStop() {
+        super.onStop();
         getActivity().unregisterReceiver(mTetherChangeReceiver);
         mTetherChangeReceiver = null;
         mWifiApEnabler.pause();
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
index 488e117..dc3a96b 100644
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -37,9 +37,9 @@
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceClickListener;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.speech.tts.TextToSpeech;
@@ -126,6 +126,7 @@
         mDefaultLocVariant = currentLocale.getVariant();
 
         mTts = new TextToSpeech(activity, this);
+        initClickers();
     }
 
 
@@ -136,7 +137,6 @@
             // whenever we return to this screen, we don't know the state of the
             // system, so we have to recheck that we can play the demo, or it must be disabled.
             // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
-            initClickers();
             updateWidgetState();
             checkVoiceData();
         }
@@ -357,7 +357,6 @@
             mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
             mTts.setSpeechRate(mDefaultRate/100.0f);
             initDefaultSettings();
-            initClickers();
             updateWidgetState();
             checkVoiceData();
             mTtsStarted = true;
diff --git a/src/com/android/settings/UserDictionarySettings.java b/src/com/android/settings/UserDictionarySettings.java
index f1e74ac..6386c86 100644
--- a/src/com/android/settings/UserDictionarySettings.java
+++ b/src/com/android/settings/UserDictionarySettings.java
@@ -31,7 +31,6 @@
 import android.text.InputType;
 import android.util.Log;
 import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -39,7 +38,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.widget.AlphabetIndexer;
 import android.widget.EditText;
 import android.widget.ListAdapter;
@@ -47,6 +46,7 @@
 import android.widget.SectionIndexer;
 import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
 
 import java.util.Locale;
 
@@ -198,8 +198,10 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        menu.add(0, OPTIONS_MENU_ADD, 0, R.string.user_dict_settings_add_menu_title)
+        MenuItem actionItem =
+                menu.add(0, OPTIONS_MENU_ADD, 0, R.string.user_dict_settings_add_menu_title)
                 .setIcon(R.drawable.ic_menu_add);
+        actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
     }
 
     @Override
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 4c43712..d635403 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -20,8 +20,8 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.graphics.drawable.Drawable;
@@ -29,9 +29,9 @@
 import android.os.SystemProperties;
 import android.preference.Preference;
 import android.preference.PreferenceGroup;
+import android.preference.PreferenceActivity.Header;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.Log;
 
 import java.util.List;
 
@@ -203,6 +203,66 @@
         return false;
     }
 
+    public static boolean updateHeaderToSpecificActivityFromMetaDataOrRemove(Context context,
+            List<Header> target, Header header) {
+
+        Intent intent = header.intent;
+        if (intent != null) {
+            // Find the activity that is in the system image
+            PackageManager pm = context.getPackageManager();
+            List<ResolveInfo> list = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);
+            int listSize = list.size();
+            for (int i = 0; i < listSize; i++) {
+                ResolveInfo resolveInfo = list.get(i);
+                if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+                        != 0) {
+                    Drawable icon = null;
+                    String title = null;
+                    String summary = null;
+
+                    // Get the activity's meta-data
+                    try {
+                        Resources res = pm.getResourcesForApplication(
+                                resolveInfo.activityInfo.packageName);
+                        Bundle metaData = resolveInfo.activityInfo.metaData;
+
+                        if (res != null && metaData != null) {
+                            icon = res.getDrawable(metaData.getInt(META_DATA_PREFERENCE_ICON));
+                            title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
+                            summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY));
+                        }
+                    } catch (NameNotFoundException e) {
+                        // Ignore
+                    } catch (NotFoundException e) {
+                        // Ignore
+                    }
+
+                    // Set the preference title to the activity's label if no
+                    // meta-data is found
+                    if (TextUtils.isEmpty(title)) {
+                        title = resolveInfo.loadLabel(pm).toString();
+                    }
+
+                    // Set icon, title and summary for the preference
+                    // TODO:
+                    //header.icon = icon;
+                    header.title = title;
+                    header.summary = summary;
+                    // Replace the intent with this specific activity
+                    header.intent = new Intent().setClassName(resolveInfo.activityInfo.packageName,
+                            resolveInfo.activityInfo.name);
+
+                    return true;
+                }
+            }
+        }
+
+        // Did not find a matching activity, so remove the preference
+        if (target.remove(header)) System.err.println("Removed " + header.id);
+
+        return false;
+    }
+
     /**
      * Returns true if Monkey is running.
      */