OSDN Git Service

Breadcrumbs in the action bar for navigating up one level and showing current title.
authorAmith Yamasani <yamasani@google.com>
Sun, 12 Sep 2010 15:17:50 +0000 (08:17 -0700)
committerAmith Yamasani <yamasani@google.com>
Sun, 12 Sep 2010 18:47:26 +0000 (11:47 -0700)
Change-Id: I595e06549b888bd67c6dddd599a4cc77416c3a41

AndroidManifest.xml
res/drawable-hdpi/nav_divider.png [new file with mode: 0644]
res/drawable-mdpi/nav_divider.png [new file with mode: 0644]
res/layout/settings_actionbar.xml [new file with mode: 0644]
src/com/android/settings/Settings.java
src/com/android/settings/SettingsPreferenceFragment.java

index e93cb2e..b6a422e 100644 (file)
@@ -49,7 +49,7 @@
 
         <activity android:name="Settings" android:label="@string/settings_label"
                 android:taskAffinity="com.android.settings"
-                android:theme="@android:style/Theme.WithActionBar">
+                android:theme="@android:style/Theme.Holo">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.settings.SETTINGS" />
diff --git a/res/drawable-hdpi/nav_divider.png b/res/drawable-hdpi/nav_divider.png
new file mode 100644 (file)
index 0000000..7ca3e61
Binary files /dev/null and b/res/drawable-hdpi/nav_divider.png differ
diff --git a/res/drawable-mdpi/nav_divider.png b/res/drawable-mdpi/nav_divider.png
new file mode 100644 (file)
index 0000000..c9413d7
Binary files /dev/null and b/res/drawable-mdpi/nav_divider.png differ
diff --git a/res/layout/settings_actionbar.xml b/res/layout/settings_actionbar.xml
new file mode 100644 (file)
index 0000000..6388025
--- /dev/null
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="horizontal"
+        android:padding="4dip"
+        android:gravity="center_vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent">
+
+    <!-- ImageView
+            android:src="@drawable/ic_launcher_settings"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="4dip"
+            android:layout_marginRight="4dip"
+    /-->
+
+    <view class="com.android.settings.Settings$BreadCrumbs"
+            android:id="@+id/bread_crumbs"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:orientation="horizontal">
+
+        <TextView android:id="@+id/level_up_title"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                style="?android:attr/textAppearanceMediumInverse"
+                />
+
+        <ImageView
+                android:id="@+id/level_divider"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_marginTop="4dip"
+                android:layout_marginBottom="4dip"
+                android:layout_marginLeft="12dip"
+                android:layout_marginRight="12dip"
+                android:src="@drawable/nav_divider"/>
+
+        <TextView android:id="@+id/level_current_title"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                style="?android:attr/textAppearanceMediumInverse"
+                />
+    </view>
+</LinearLayout>
index 2ce0bcc..50aa1df 100644 (file)
@@ -18,6 +18,7 @@ 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;
@@ -25,8 +26,13 @@ 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 java.util.ArrayList;
 
@@ -37,6 +43,8 @@ public class Settings extends Activity
         implements PreferenceFragment.OnPreferenceStartFragmentCallback,
         SettingsPreferenceFragment.OnStateListener {
 
+    private static final boolean DBG = false;
+
     private static final String TAG = "Settings";
 
     private static final String KEY_PARENT = "parent";
@@ -52,22 +60,13 @@ public class Settings extends Activity
 
     public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
 
-    // Temporary, until all top-level settings are converted to fragments
     private static final String BACK_STACK_PREFS = ":settings:prefs";
 
     private View mPrefsPane;
     private View mMainPane;
     private boolean mSinglePane;
 
-    private ArrayList<CharSequence> mTrail = new ArrayList<CharSequence>();
-
-    /*
-    @Override
-    protected void onResume() {
-        super.onResume();
-        findPreference(KEY_CALL_SETTINGS).setEnabled(!AirplaneModeEnabler.isAirplaneModeOn(this));
-    }
-    */
+    private BreadCrumbs mBreadCrumbs;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -82,6 +81,8 @@ public class Settings extends Activity
         String initialFragment = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
         Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
 
+        createActionBar();
+
         if (mSinglePane) {
             if (initialFragment != null) {
                 showFragment(initialFragment, initialArguments);
@@ -111,11 +112,21 @@ public class Settings extends Activity
         }
     }
 
+    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);
+    }
+
     boolean showFragment(Preference preference) {
         if (mSinglePane) {
             startWithFragment(preference.getFragment(), preference.getExtras());
             return false;
         } else {
+            mBreadCrumbs.clear();
             return showFragment(preference.getFragment(), preference.getExtras());
         }
     }
@@ -129,10 +140,13 @@ public class Settings extends Activity
     }
 
     private boolean showFragment(String fragmentClass, Bundle extras) {
-        Fragment f = Fragment.instantiate(this, fragmentClass, extras);
+        if (DBG) Log.d(TAG, "showFragment");
+       Fragment f = Fragment.instantiate(this, fragmentClass, extras);
         if (f instanceof SettingsPreferenceFragment) {
             ((SettingsPreferenceFragment) f).setOnStateListener(this);
         }
+        mBreadCrumbs.clear();
+        getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
         getFragmentManager().openTransaction().replace(R.id.prefs, f).commit();
         return true;
     }
@@ -140,41 +154,28 @@ public class Settings extends Activity
     private void addToBreadCrumbs(Fragment fragment) {
         final CharSequence title = ((PreferenceFragment) fragment)
                 .getPreferenceScreen().getTitle();
-        if (mSinglePane) mTrail.clear();
-        if (mTrail.size() == 0 || !TextUtils.equals(title, mTrail.get(mTrail.size() - 1))) {
-            mTrail.add(title);
-            updateTitle();
+        if (mSinglePane) {
+            mBreadCrumbs.clear();
         }
+        mBreadCrumbs.push(title);
     }
 
     private void removeFromBreadCrumbs(Fragment fragment) {
-        if (mTrail.size() > 0) {
-            mTrail.remove(mTrail.size() - 1);
-        }
-        updateTitle();
-    }
-
-    private void updateTitle() {
-        String trail = "";
-        for (CharSequence trailPart : mTrail) {
-            if (trail.length() != 0)
-                trail += " | ";
-            trail = trail + trailPart;
-        }
-        setTitle(trail);
+        mBreadCrumbs.pop(((PreferenceFragment) fragment).getPreferenceScreen().getTitle());
+        mBreadCrumbs.update();
     }
 
     public void onCreated(SettingsPreferenceFragment fragment) {
-        Log.d(TAG, "Fragment created " + fragment + " (name: " + fragment.getClass() + ")");
+        if (DBG) Log.d(TAG, "Fragment created " + fragment);
         addToBreadCrumbs(fragment);
     }
 
     public void onDestroyed(SettingsPreferenceFragment fragment) {
-        removeFromBreadCrumbs(fragment);
         Log.d(TAG, "Fragment destroyed " + fragment + " (name: " + fragment.getClass() + ")");
     }
 
     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
+        if (DBG) Log.d(TAG, "onPreferenceStartFragment");
         Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
         if (f instanceof SettingsPreferenceFragment) {
             ((SettingsPreferenceFragment) f).setOnStateListener(this);
@@ -184,6 +185,13 @@ public class Settings extends Activity
         return true;
     }
 
+    @Override
+    public void onBackPressed() {
+        mBreadCrumbs.pop();
+        mBreadCrumbs.update();
+        super.onBackPressed();
+    }
+
     public static class TopLevelSettings extends PreferenceFragment {
 
         private IconPreferenceScreen mHighlightedPreference;
@@ -198,6 +206,21 @@ public class Settings extends Activity
             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);
@@ -247,4 +270,91 @@ public class Settings extends Activity
             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();
+            }
+        }
+    }
 }
index d10fda3..bddfb2b 100644 (file)
@@ -51,6 +51,8 @@ public class SettingsPreferenceFragment extends PreferenceFragment {
 
     private Button mNextButton;
 
+    private boolean mReportedCreation;
+
     interface OnStateListener {
 
         void onCreated(SettingsPreferenceFragment fragment);
@@ -65,8 +67,10 @@ public class SettingsPreferenceFragment extends PreferenceFragment {
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
-        if (mOnStateListener != null) {
+        if (mOnStateListener != null && !mReportedCreation) {
             mOnStateListener.onCreated(this);
+            // So that we don't report it on the way back to this fragment
+            mReportedCreation = true;
         }
 
         setupButtonBar();