OSDN Git Service

am cb818619: Update power usage UI to follow WIFI data changes.
authorDianne Hackborn <hackbod@google.com>
Fri, 17 Sep 2010 22:20:06 +0000 (15:20 -0700)
committerAndroid Git Automerger <android-git-automerger@android.com>
Fri, 17 Sep 2010 22:20:06 +0000 (15:20 -0700)
Merge commit 'cb818619c669d4257a4df969dd03eff479ba84d0' into gingerbread-plus-aosp

* commit 'cb818619c669d4257a4df969dd03eff479ba84d0':
  Update power usage UI to follow WIFI data changes.

28 files changed:
AndroidManifest.xml
res/layout/bluetooth_pin_entry.xml
res/xml/settings.xml
src/com/android/settings/ApnEditor.java
src/com/android/settings/DateTimeSettingsSetupWizard.java
src/com/android/settings/IconPreferenceScreen.java
src/com/android/settings/LanguageSettings.java
src/com/android/settings/ProgressCategory.java
src/com/android/settings/ProxySelector.java
src/com/android/settings/SecuritySettings.java
src/com/android/settings/Settings.java
src/com/android/settings/SettingsSafetyLegalActivity.java
src/com/android/settings/SoundSettings.java
src/com/android/settings/TetherSettings.java
src/com/android/settings/UsageStats.java
src/com/android/settings/Utils.java
src/com/android/settings/bluetooth/BluetoothSettings.java
src/com/android/settings/bluetooth/CachedBluetoothDevice.java
src/com/android/settings/quicklaunch/QuickLaunchSettings.java
src/com/android/settings/vpn/VpnEditor.java
tests/AndroidManifest.xml
tests/res/drawable/ic_settings_applications.png [new file with mode: 0755]
tests/res/layout/manufacturer_main.xml [new file with mode: 0644]
tests/res/layout/operator_main.xml [new file with mode: 0644]
tests/res/values/strings.xml
tests/src/com/android/settings/SettingsHookTests.java [new file with mode: 0644]
tests/src/com/android/settings/tests/Manufacturer.java [new file with mode: 0644]
tests/src/com/android/settings/tests/Operator.java [new file with mode: 0644]

index 1dacea4..1c1bb6d 100644 (file)
         </activity>
 
         <activity android:name=".vpn.VpnSettings"
+                android:label="@string/vpn_settings_title"
                 android:configChanges="orientation|keyboardHidden"
                 android:clearTaskOnLaunch="true">
             <intent-filter>
                 <action android:name="android.net.vpn.SETTINGS" />
                 <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>
 
index 16b75fc..b0c1216 100644 (file)
@@ -44,8 +44,9 @@
             android:layout_marginTop="20dip"
             android:layout_marginLeft="20dip"
             android:layout_marginRight="20dip"
+            android:inputType="textPassword"
             android:singleLine="true" />
 
     </LinearLayout>
 
-</ScrollView>
\ No newline at end of file
+</ScrollView>
index 0f19442..326c494 100644 (file)
     android:title="@string/settings_label"
     android:key="parent">
 
+        <!-- Operator hook -->
+
+        <com.android.settings.IconPreferenceScreen
+            android:key="operator_settings">
+            <intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" />
+        </com.android.settings.IconPreferenceScreen>
+
+        <!-- Manufacturer hook -->
+
+        <com.android.settings.IconPreferenceScreen
+            android:key="manufacturer_settings">
+            <intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" />
+        </com.android.settings.IconPreferenceScreen>
+
         <com.android.settings.IconPreferenceScreen
             android:title="@string/radio_controls_title"
             settings:icon="@drawable/ic_settings_wireless">
index e097854..72dba1a 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.settings;
 
 import android.app.AlertDialog;
+import android.app.Dialog;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Intent;
@@ -51,6 +52,7 @@ public class ApnEditor extends PreferenceActivity
     private static final int MENU_DELETE = Menu.FIRST;
     private static final int MENU_SAVE = Menu.FIRST + 1;
     private static final int MENU_CANCEL = Menu.FIRST + 2;
+    private static final int ERROR_DIALOG_ID = 0;
 
     private static String sNotSet;
     private EditTextPreference mName;
@@ -347,19 +349,8 @@ public class ApnEditor extends PreferenceActivity
         String mcc = checkNotSet(mMcc.getText());
         String mnc = checkNotSet(mMnc.getText());
 
-        String errorMsg = null;
-        if (name.length() < 1) {
-            errorMsg = mRes.getString(R.string.error_name_empty);
-        } else if (apn.length() < 1) {
-            errorMsg = mRes.getString(R.string.error_apn_empty);
-        } else if (mcc.length() != 3) {
-            errorMsg = mRes.getString(R.string.error_mcc_not3);
-        } else if ((mnc.length() & 0xFFFE) != 2) {
-            errorMsg = mRes.getString(R.string.error_mnc_not23);
-        }
-
-        if (errorMsg != null && !force) {
-            showErrorMessage(errorMsg);
+        if (getErrorMsg() != null && !force) {
+            showDialog(ERROR_DIALOG_ID);
             return false;
         }
 
@@ -414,12 +405,54 @@ public class ApnEditor extends PreferenceActivity
         return true;
     }
 
-    private void showErrorMessage(String message) {
-        new AlertDialog.Builder(this)
-            .setTitle(R.string.error_title)
-            .setMessage(message)
-            .setPositiveButton(android.R.string.ok, null)
-            .show();
+    private String getErrorMsg() {
+        String errorMsg = null;
+
+        String name = checkNotSet(mName.getText());
+        String apn = checkNotSet(mApn.getText());
+        String mcc = checkNotSet(mMcc.getText());
+        String mnc = checkNotSet(mMnc.getText());
+
+        if (name.length() < 1) {
+            errorMsg = mRes.getString(R.string.error_name_empty);
+        } else if (apn.length() < 1) {
+            errorMsg = mRes.getString(R.string.error_apn_empty);
+        } else if (mcc.length() != 3) {
+            errorMsg = mRes.getString(R.string.error_mcc_not3);
+        } else if ((mnc.length() & 0xFFFE) != 2) {
+            errorMsg = mRes.getString(R.string.error_mnc_not23);
+        }
+
+        return errorMsg;
+    }
+
+    @Override
+    protected Dialog onCreateDialog(int id) {
+
+        if (id == ERROR_DIALOG_ID) {
+            String msg = getErrorMsg();
+
+            return new AlertDialog.Builder(this)
+                    .setTitle(R.string.error_title)
+                    .setPositiveButton(android.R.string.ok, null)
+                    .setMessage(msg)
+                    .create();
+        }
+
+        return super.onCreateDialog(id);
+    }
+
+    @Override
+    protected void onPrepareDialog(int id, Dialog dialog) {
+        super.onPrepareDialog(id, dialog);
+
+        if (id == ERROR_DIALOG_ID) {
+            String msg = getErrorMsg();
+
+            if (msg != null) {
+                ((AlertDialog)dialog).setMessage(msg);
+            }
+        }
     }
 
     private void deleteApn() {
index 8dd970b..a6a60c1 100644 (file)
@@ -20,7 +20,6 @@ import android.os.Bundle;
 import android.view.View;
 import android.view.Window;
 import android.view.View.OnClickListener;
-import android.widget.LinearLayout;
 
 public class DateTimeSettingsSetupWizard extends DateTimeSettings implements OnClickListener {
     private View mNextButton;
index c7c5303..31abf0a 100644 (file)
@@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable;
 import android.preference.Preference;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 
 public class IconPreferenceScreen extends Preference {
@@ -48,4 +49,26 @@ public class IconPreferenceScreen extends Preference {
             imageView.setImageDrawable(mIcon);
         }
     }
+
+    /**
+     * Sets the icon for this Preference with a Drawable.
+     *
+     * @param icon The icon for this Preference
+     */
+    public void setIcon(Drawable icon) {
+        if ((icon == null && mIcon != null) || (icon != null && !icon.equals(mIcon))) {
+            mIcon = icon;
+            notifyChanged();
+        }
+    }
+
+    /**
+     * Returns the icon of this Preference.
+     *
+     * @return The icon.
+     * @see #setIcon(Drawable)
+     */
+    public Drawable getIcon() {
+        return mIcon;
+    }
 }
index 91d260c..1252eec 100644 (file)
@@ -55,6 +55,8 @@ public class LanguageSettings extends PreferenceActivity {
     
     private String mLastInputMethodId;
     private String mLastTickedInputMethodId;
+
+    private AlertDialog mDialog = null;
     
     static public String getInputMethodIdFromKey(String key) {
         return key;
@@ -255,29 +257,35 @@ public class LanguageSettings extends PreferenceActivity {
                 if (selImi == null) {
                     return super.onPreferenceTreeClick(preferenceScreen, preference);
                 }
-                AlertDialog d = (new AlertDialog.Builder(this))
-                        .setTitle(android.R.string.dialog_alert_title)
-                        .setIcon(android.R.drawable.ic_dialog_alert)
-                        .setMessage(getString(R.string.ime_security_warning,
-                                selImi.getServiceInfo().applicationInfo.loadLabel(
-                                        getPackageManager())))
-                        .setCancelable(true)
-                        .setPositiveButton(android.R.string.ok,
-                                new DialogInterface.OnClickListener() {
-                                    public void onClick(DialogInterface dialog, int which) {
-                                        chkPref.setChecked(true);
-                                        mLastTickedInputMethodId = id;
-                                    }
-                            
-                        })
-                        .setNegativeButton(android.R.string.cancel,
-                                new DialogInterface.OnClickListener() {
-                                    public void onClick(DialogInterface dialog, int which) {
-                                    }
-                            
-                        })
-                        .create();
-                d.show();
+                if (mDialog == null) {
+                    mDialog = (new AlertDialog.Builder(this))
+                            .setTitle(android.R.string.dialog_alert_title)
+                            .setIcon(android.R.drawable.ic_dialog_alert)
+                            .setCancelable(true)
+                            .setPositiveButton(android.R.string.ok,
+                                    new DialogInterface.OnClickListener() {
+                                        public void onClick(DialogInterface dialog, int which) {
+                                            chkPref.setChecked(true);
+                                            mLastTickedInputMethodId = id;
+                                        }
+
+                            })
+                            .setNegativeButton(android.R.string.cancel,
+                                    new DialogInterface.OnClickListener() {
+                                        public void onClick(DialogInterface dialog, int which) {
+                                        }
+
+                            })
+                            .create();
+                } else {
+                    if (mDialog.isShowing()) {
+                        mDialog.dismiss();
+                    }
+                }
+                mDialog.setMessage(getString(R.string.ime_security_warning,
+                        selImi.getServiceInfo().applicationInfo.loadLabel(
+                                getPackageManager())));
+                mDialog.show();
             } else if (id.equals(mLastTickedInputMethodId)) {
                 mLastTickedInputMethodId = null;
             }
@@ -302,4 +310,13 @@ public class LanguageSettings extends PreferenceActivity {
         return super.onPreferenceTreeClick(preferenceScreen, preference);
     }
 
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+        }
+    }
+
 }
index 15810b3..f611137 100644 (file)
@@ -26,7 +26,8 @@ import java.util.Map;
 public class ProgressCategory extends PreferenceCategory {
 
     private boolean mProgress = false;
-    
+    private View oldView = null;
+
     public ProgressCategory(Context context, AttributeSet attrs) {
         super(context, attrs);
         setLayoutResource(R.layout.preference_progress_category);
@@ -41,6 +42,13 @@ public class ProgressCategory extends PreferenceCategory {
         int visibility = mProgress ? View.VISIBLE : View.INVISIBLE;
         textView.setVisibility(visibility);
         progressBar.setVisibility(visibility);
+
+        if (oldView != null) {
+            oldView.findViewById(R.id.scanning_progress).setVisibility(View.GONE);
+            oldView.findViewById(R.id.scanning_text).setVisibility(View.GONE);
+            oldView.setVisibility(View.GONE);
+        }
+        oldView = view;
     }
     
     /**
index 80fe3c9..66c81c6 100644 (file)
@@ -18,6 +18,7 @@ package com.android.settings;
 
 import android.app.Activity;
 import android.app.AlertDialog;
+import android.app.Dialog;
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.net.Proxy;
@@ -73,6 +74,7 @@ public class ProxySelector extends Activity
         HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
     }
 
+    private static final int ERROR_DIALOG_ID = 0;
 
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -84,13 +86,32 @@ public class ProxySelector extends Activity
         populateFields(false);
     }
 
-    protected void showError(int error) {
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        if (id == ERROR_DIALOG_ID) {
+            String hostname = mHostnameField.getText().toString().trim();
+            String portStr = mPortField.getText().toString().trim();
+            String msg = getString(validate(hostname, portStr));
+
+            return new AlertDialog.Builder(this)
+                    .setTitle(R.string.proxy_error)
+                    .setPositiveButton(R.string.proxy_error_dismiss, null)
+                    .setMessage(msg)
+                    .create();
+        }
+        return super.onCreateDialog(id);
+    }
 
-        new AlertDialog.Builder(this)
-                .setTitle(R.string.proxy_error)
-                .setMessage(error)
-                .setPositiveButton(R.string.proxy_error_dismiss, null)
-                .show();
+    @Override
+    protected void onPrepareDialog(int id, Dialog dialog) {
+        super.onPrepareDialog(id, dialog);
+
+        if (id == ERROR_DIALOG_ID) {
+            String hostname = mHostnameField.getText().toString().trim();
+            String portStr = mPortField.getText().toString().trim();
+            String msg = getString(validate(hostname, portStr));
+            ((AlertDialog)dialog).setMessage(msg);
+        }
     }
 
     void initView() {
@@ -188,7 +209,7 @@ public class ProxySelector extends Activity
 
         int result = validate(hostname, portStr);
         if (result > 0) {
-            showError(result);
+            showDialog(ERROR_DIALOG_ID);
             return false;
         }
 
index 05a655a..454ea60 100644 (file)
@@ -20,7 +20,6 @@ package com.android.settings;
 import java.util.Observable;
 import java.util.Observer;
 
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.admin.DevicePolicyManager;
@@ -34,18 +33,15 @@ import android.location.LocationManager;
 import android.os.Bundle;
 import android.os.SystemProperties;
 import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceManager;
 import android.preference.PreferenceScreen;
-import android.preference.Preference.OnPreferenceChangeListener;
 import android.provider.Settings;
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.telephony.TelephonyManager;
-import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
 import android.widget.Toast;
index b37c340..4ecf85b 100644 (file)
@@ -21,7 +21,6 @@ import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceGroup;
-import android.telephony.TelephonyManager;
 
 public class Settings extends PreferenceActivity {
 
@@ -31,13 +30,14 @@ public class Settings extends PreferenceActivity {
     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";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         
         addPreferencesFromResource(R.xml.settings);
-        
-        int activePhoneType = TelephonyManager.getDefault().getPhoneType();
 
         PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT);
         Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_SYNC_SETTINGS, 0);
@@ -47,6 +47,11 @@ public class Settings extends PreferenceActivity {
         if (getResources().getBoolean(R.bool.has_dock_settings) == false && dockSettings != null) {
             parent.removePreference(dockSettings);
         }
+
+        Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(this, parent,
+                KEY_OPERATOR_SETTINGS);
+        Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(this, parent,
+                KEY_MANUFACTURER_SETTINGS);
     }
     
     @Override
index 0c51928..368ee1d 100644 (file)
@@ -40,6 +40,8 @@ public class SettingsSafetyLegalActivity extends AlertActivity
 
     private WebView mWebView;
 
+    private AlertDialog mErrorDialog = null;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -85,14 +87,31 @@ public class SettingsSafetyLegalActivity extends AlertActivity
     }
 
     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, this)
-                .setOnCancelListener(this)
-                .setCancelable(true)
-                .show();
+        if (mErrorDialog == null) {
+            mErrorDialog = new AlertDialog.Builder(this)
+                    .setTitle(R.string.settings_safetylegal_activity_title)
+                    .setPositiveButton(android.R.string.ok, this)
+                    .setOnCancelListener(this)
+                    .setCancelable(true)
+                    .create();
+        } else {
+            if (mErrorDialog.isShowing()) {
+                mErrorDialog.dismiss();
+            }
+        }
+        mErrorDialog.setMessage(getResources()
+                .getString(R.string.settings_safetylegal_activity_unreachable, url));
+        mErrorDialog.show();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        if (mErrorDialog != null) {
+            mErrorDialog.dismiss();
+            mErrorDialog = null;
+        }
     }
 
     @Override
index bfb5566..a735268 100644 (file)
@@ -16,8 +16,6 @@
 
 package com.android.settings;
 
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
index 9eee4e0..b924571 100644 (file)
@@ -21,7 +21,6 @@ import com.android.settings.wifi.WifiApEnabler;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -33,8 +32,6 @@ import android.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceScreen;
-import android.provider.Settings;
-import android.util.Log;
 import android.webkit.WebView;
 
 import java.io.InputStream;
@@ -67,7 +64,6 @@ public class TetherSettings extends PreferenceActivity {
     private BroadcastReceiver mTetherChangeReceiver;
 
     private String[] mUsbRegexs;
-    private ArrayList mUsbIfaces;
 
     private String[] mWifiRegexs;
 
@@ -161,7 +157,8 @@ public class TetherSettings extends PreferenceActivity {
                         ConnectivityManager.EXTRA_ACTIVE_TETHER);
                 ArrayList<String> errored = intent.getStringArrayListExtra(
                         ConnectivityManager.EXTRA_ERRORED_TETHER);
-                updateState(available.toArray(), active.toArray(), errored.toArray());
+                updateState((String[]) available.toArray(), (String[]) active.toArray(),
+                        (String[]) errored.toArray());
             } else if (intent.getAction().equals(Intent.ACTION_MEDIA_SHARED) ||
                        intent.getAction().equals(Intent.ACTION_MEDIA_UNSHARED)) {
                 updateState();
@@ -205,8 +202,8 @@ public class TetherSettings extends PreferenceActivity {
         updateState(available, tethered, errored);
     }
 
-    private void updateState(Object[] available, Object[] tethered,
-            Object[] errored) {
+    private void updateState(String[] available, String[] tethered,
+            String[] errored) {
         ConnectivityManager cm =
                 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
         boolean usbTethered = false;
@@ -215,8 +212,7 @@ public class TetherSettings extends PreferenceActivity {
         boolean usbErrored = false;
         boolean massStorageActive =
                 Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
-        for (Object o : available) {
-            String s = (String)o;
+        for (String s : available) {
             for (String regex : mUsbRegexs) {
                 if (s.matches(regex)) {
                     usbAvailable = true;
@@ -226,14 +222,12 @@ public class TetherSettings extends PreferenceActivity {
                 }
             }
         }
-        for (Object o : tethered) {
-            String s = (String)o;
+        for (String s : tethered) {
             for (String regex : mUsbRegexs) {
                 if (s.matches(regex)) usbTethered = true;
             }
         }
-        for (Object o: errored) {
-            String s = (String)o;
+        for (String s: errored) {
             for (String regex : mUsbRegexs) {
                 if (s.matches(regex)) usbErrored = true;
             }
index fcb6990..f67eeec 100755 (executable)
@@ -52,7 +52,7 @@ import android.widget.AdapterView.OnItemSelectedListener;
  */
 public class UsageStats extends Activity implements OnItemSelectedListener {
     private static final String TAG="UsageStatsActivity";
-    private static final boolean localLOGV = true;
+    private static final boolean localLOGV = false;
     private Spinner mTypeSpinner;
     private ListView mListView;
     private IUsageStats mUsageStatsService;
index d4f1f11..b29ec06 100644 (file)
@@ -22,8 +22,14 @@ import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.SystemProperties;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.PreferenceGroup;
+import android.text.TextUtils;
 
 import java.util.List;
 
@@ -35,6 +41,24 @@ public class Utils {
     public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1;
 
     /**
+     * Name of the meta-data item that should be set in the AndroidManifest.xml
+     * to specify the icon that should be displayed for the preference.
+     */
+    private static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon";
+
+    /**
+     * Name of the meta-data item that should be set in the AndroidManifest.xml
+     * to specify the title that should be displayed for the preference.
+     */
+    private static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";
+
+    /**
+     * Name of the meta-data item that should be set in the AndroidManifest.xml
+     * to specify the summary text that should be displayed for the preference.
+     */
+    private static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary";
+
+    /**
      * Finds a matching activity for a preference's intent. If a matching
      * activity is not found, it will remove the preference.
      *
@@ -90,10 +114,97 @@ public class Utils {
     }
 
     /**
+     * Finds a matching activity for a preference's intent. If a matching
+     * activity is not found, it will remove the preference. The icon, title and
+     * summary of the preference will also be updated with the values retrieved
+     * from the activity's meta-data elements. If no meta-data elements are
+     * specified then the preference title will be set to match the label of the
+     * activity, an icon and summary text will not be displayed.
+     *
+     * @param context The context.
+     * @param parentPreferenceGroup The preference group that contains the
+     *            preference whose intent is being resolved.
+     * @param preferenceKey The key of the preference whose intent is being
+     *            resolved.
+     *
+     * @return Whether an activity was found. If false, the preference was
+     *         removed.
+     *
+     * @see {@link #META_DATA_PREFERENCE_ICON}
+     *      {@link #META_DATA_PREFERENCE_TITLE}
+     *      {@link #META_DATA_PREFERENCE_SUMMARY}
+     */
+    public static boolean updatePreferenceToSpecificActivityFromMetaDataOrRemove(Context context,
+            PreferenceGroup parentPreferenceGroup, String preferenceKey) {
+
+        IconPreferenceScreen preference = (IconPreferenceScreen)parentPreferenceGroup
+                .findPreference(preferenceKey);
+        if (preference == null) {
+            return false;
+        }
+
+        Intent intent = preference.getIntent();
+        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
+                    preference.setIcon(icon);
+                    preference.setTitle(title);
+                    preference.setSummary(summary);
+
+                    // Replace the intent with this specific activity
+                    preference.setIntent(new Intent().setClassName(
+                            resolveInfo.activityInfo.packageName,
+                            resolveInfo.activityInfo.name));
+
+                   return true;
+                }
+            }
+        }
+
+        // Did not find a matching activity, so remove the preference
+        parentPreferenceGroup.removePreference(preference);
+
+        return false;
+    }
+
+    /**
      * Returns true if Monkey is running.
      */
     public static boolean isMonkeyRunning() {
         return SystemProperties.getBoolean("ro.monkey", false);
     }
-
 }
index 1e73b2d..78c531c 100644 (file)
@@ -188,7 +188,8 @@ public class BluetoothSettings extends PreferenceActivity
         super.onPause();
 
         mLocalManager.setForegroundActivity(null);
-
+        mDevicePreferenceMap.clear();
+        mDeviceList.removeAll();
         unregisterReceiver(mReceiver);
 
         mLocalManager.unregisterCallback(this);
index 9b16005..0e969da 100644 (file)
@@ -67,6 +67,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
 
     private final LocalBluetoothManager mLocalManager;
 
+    private AlertDialog mDialog = null;
+
     private List<Callback> mCallbacks = new ArrayList<Callback>();
 
     /**
@@ -199,12 +201,29 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
             }
         };
 
-        new AlertDialog.Builder(context)
-                .setTitle(getName())
-                .setMessage(message)
-                .setPositiveButton(android.R.string.ok, disconnectListener)
-                .setNegativeButton(android.R.string.cancel, null)
-                .show();
+        if (mDialog == null) {
+            mDialog = new AlertDialog.Builder(context)
+                    .setPositiveButton(android.R.string.ok, disconnectListener)
+                    .setNegativeButton(android.R.string.cancel, null)
+                    .create();
+        } else {
+            if (mDialog.isShowing()) {
+                mDialog.dismiss();
+            }
+        }
+        mDialog.setTitle(getName());
+        mDialog.setMessage(message);
+        mDialog.show();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+        }
+
+        super.finalize();
     }
 
     public void connect() {
index ca5d3ab..2d2b01c 100644 (file)
@@ -204,7 +204,7 @@ public class QuickLaunchSettings extends PreferenceActivity implements
         return true;
     }
 
-    public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
+    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
         
         // Open the clear shortcut dialog
         Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(position);
@@ -314,7 +314,7 @@ public class QuickLaunchSettings extends PreferenceActivity implements
             String intentUri = c.getString(intentColumn);
             PackageManager packageManager = getPackageManager();
             try {
-                Intent intent = Intent.getIntent(intentUri);
+                Intent intent = Intent.parseUri(intentUri, 0);
                 ResolveInfo info = packageManager.resolveActivity(intent, 0);
                 if (info != null) {
                     title = info.loadLabel(packageManager);
index 497f4bf..349befb 100644 (file)
@@ -19,6 +19,7 @@ package com.android.settings.vpn;
 import com.android.settings.R;
 
 import android.app.AlertDialog;
+import android.app.Dialog;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.net.vpn.L2tpIpsecProfile;
@@ -44,6 +45,7 @@ import android.view.View;
 public class VpnEditor extends PreferenceActivity {
     private static final int MENU_SAVE = Menu.FIRST;
     private static final int MENU_CANCEL = Menu.FIRST + 1;
+    private static final int CONFIRM_DIALOG_ID = 0;
     private static final String KEY_PROFILE = "profile";
     private static final String KEY_ORIGINAL_PROFILE_NAME = "orig_profile_name";
 
@@ -98,7 +100,7 @@ public class VpnEditor extends PreferenceActivity {
 
             case MENU_CANCEL:
                 if (profileChanged()) {
-                    showCancellationConfirmDialog();
+                    showDialog(CONFIRM_DIALOG_ID);
                 } else {
                     finish();
                 }
@@ -171,21 +173,39 @@ public class VpnEditor extends PreferenceActivity {
         }
     }
 
-    private void showCancellationConfirmDialog() {
-        new AlertDialog.Builder(this)
-                .setTitle(android.R.string.dialog_alert_title)
-                .setIcon(android.R.drawable.ic_dialog_alert)
-                .setMessage(mAddingProfile
-                        ? R.string.vpn_confirm_add_profile_cancellation
-                        : R.string.vpn_confirm_edit_profile_cancellation)
-                .setPositiveButton(R.string.vpn_yes_button,
-                        new DialogInterface.OnClickListener() {
-                            public void onClick(DialogInterface dialog, int w) {
-                                finish();
-                            }
-                        })
-                .setNegativeButton(R.string.vpn_mistake_button, null)
-                .show();
+
+    @Override
+    protected Dialog onCreateDialog(int id) {
+
+        if (id == CONFIRM_DIALOG_ID) {
+            return new AlertDialog.Builder(this)
+                    .setTitle(android.R.string.dialog_alert_title)
+                    .setIcon(android.R.drawable.ic_dialog_alert)
+                    .setMessage(mAddingProfile
+                            ? R.string.vpn_confirm_add_profile_cancellation
+                            : R.string.vpn_confirm_edit_profile_cancellation)
+                    .setPositiveButton(R.string.vpn_yes_button,
+                            new DialogInterface.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int w) {
+                                    finish();
+                                }
+                            })
+                    .setNegativeButton(R.string.vpn_mistake_button, null)
+                    .create();
+        }
+
+        return super.onCreateDialog(id);
+    }
+
+    @Override
+    protected void onPrepareDialog(int id, Dialog dialog) {
+        super.onPrepareDialog(id, dialog);
+
+        if (id == CONFIRM_DIALOG_ID) {
+            ((AlertDialog)dialog).setMessage(mAddingProfile
+                    ? getString(R.string.vpn_confirm_add_profile_cancellation)
+                    : getString(R.string.vpn_confirm_edit_profile_cancellation));
+        }
     }
 
     private VpnProfile getProfile() {
index 6b9e050..e125128 100644 (file)
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity android:name="Operator" android:label="Operator Hook Test" >
+            <intent-filter>
+                <action android:name="com.android.settings.OPERATOR_APPLICATION_SETTING" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.title" android:resource="@string/operator_settings_title" />
+            <meta-data android:name="com.android.settings.summary" android:resource="@string/operator_settings_summary" />
+            <meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_settings_applications" />
+        </activity>
+        <activity android:name="Manufacturer" android:label="Manufacturer Hook Test" >
+            <intent-filter>
+                <action android:name="com.android.settings.MANUFACTURER_APPLICATION_SETTING" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.title" android:resource="@string/manufacturer_settings_title" />
+            <meta-data android:name="com.android.settings.summary" android:resource="@string/manufacturer_settings_summary" />
+            <meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_settings_applications" />
+        </activity>
     </application>
 
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.settings"
+        android:label="Settings App Tests">
+    </instrumentation>
+
     <instrumentation android:name="SettingsLaunchPerformance"
         android:targetPackage="com.android.settings"
         android:label="Settings Launch Performance">
diff --git a/tests/res/drawable/ic_settings_applications.png b/tests/res/drawable/ic_settings_applications.png
new file mode 100755 (executable)
index 0000000..5cea33f
Binary files /dev/null and b/tests/res/drawable/ic_settings_applications.png differ
diff --git a/tests/res/layout/manufacturer_main.xml b/tests/res/layout/manufacturer_main.xml
new file mode 100644 (file)
index 0000000..8f8c48f
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:orientation="vertical" android:layout_width="fill_parent"
+  android:layout_height="fill_parent">
+  <TextView android:layout_width="fill_parent"
+    android:layout_height="wrap_content" android:text="@string/manufacturer_hello" />
+</LinearLayout>
diff --git a/tests/res/layout/operator_main.xml b/tests/res/layout/operator_main.xml
new file mode 100644 (file)
index 0000000..3cf8e00
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:orientation="vertical" android:layout_width="fill_parent"
+  android:layout_height="fill_parent">
+  <TextView android:layout_width="fill_parent"
+    android:layout_height="wrap_content" android:text="@string/operator_hello" />
+</LinearLayout>
index 00de425..9fb98f9 100644 (file)
     <string name="discoverable">Discoverable</string>
     <string name="start_scan">Start scan</string>
     <string name="stop_scan">Stop scan</string>
+    <string name="operator_hello">Hello Operator!</string>
+    <string name="operator_settings_title">Operator</string>
+    <string name="operator_settings_summary">Operator hook that can be used to start activity of choice</string>
+    <string name="manufacturer_hello">Hello Manufacturer!</string>
+    <string name="manufacturer_settings_title">Manufacturer</string>
+    <string name="manufacturer_settings_summary">Manufacturer hook that can be used to start activity of choice</string>
 </resources>
diff --git a/tests/src/com/android/settings/SettingsHookTests.java b/tests/src/com/android/settings/SettingsHookTests.java
new file mode 100644 (file)
index 0000000..b14e5bc
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+package com.android.settings;
+
+import com.android.settings.tests.Manufacturer;
+import com.android.settings.tests.Operator;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceGroup;
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.util.List;
+
+/**
+ * Tests for the Settings operator/manufacturer hook.
+ *
+ * Running all tests:
+ *
+ *   make SettingsTests
+ *   adb push SettingsTests.apk /system/app/SettingsTests.apk
+ *   adb shell am instrument \
+ *    -w com.android.settings.tests/android.test.InstrumentationTestRunner
+ */
+public class SettingsHookTests extends ActivityInstrumentationTestCase2<Settings> {
+
+    private static final String PACKAGE_NAME = "com.android.settings.tests";
+
+    private static final String KEY_SETTINGS_ROOT = "parent";
+    private static final String KEY_SETTINGS_OPERATOR = "operator_settings";
+    private static final String KEY_SETTINGS_MANUFACTURER = "manufacturer_settings";
+
+    private static final String INTENT_OPERATOR_HOOK = "com.android.settings.OPERATOR_APPLICATION_SETTING";
+    private static final String INTENT_MANUFACTURER_HOOK = "com.android.settings.MANUFACTURER_APPLICATION_SETTING";
+
+    private Settings mSettings;
+
+    public SettingsHookTests() {
+        super("com.android.settings", Settings.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mSettings = getActivity();
+    }
+
+    /**
+     * Test that the operator/manufacturer settings hook test application is
+     * available and that it's installed in the device's system image.
+     */
+    public void testSettingsHookTestAppAvailable() throws Exception {
+        Context context = mSettings.getApplicationContext();
+        PackageManager pm = context.getPackageManager();
+        ApplicationInfo applicationInfo = pm.getApplicationInfo(PACKAGE_NAME, 0);
+        assertTrue((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+    }
+
+    /**
+     * Test that the operator test activity has registered an intent-filter for
+     * an action named 'android.settings.OPERATOR_APPLICATION_SETTING'.
+     */
+    public void testOperatorIntentFilter() {
+        boolean result = false;
+        Context context = mSettings.getApplicationContext();
+        PackageManager pm = context.getPackageManager();
+        Intent intent = new Intent(INTENT_OPERATOR_HOOK);
+        List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
+        for (ResolveInfo resolveInfo : list) {
+            if (resolveInfo.activityInfo.packageName.equals(PACKAGE_NAME)) {
+                result = true;
+            }
+        }
+        assertTrue("Intent-filer not found", result);
+    }
+
+    /**
+     * Test that the manufacturer test activity has registered an intent-filter
+     * for an action named 'android.settings.MANUFACTURER_APPLICATION_SETTING'.
+     */
+    public void testManufacturerIntentFilter() {
+        boolean result = false;
+        Context context = mSettings.getApplicationContext();
+        PackageManager pm = context.getPackageManager();
+        Intent intent = new Intent(INTENT_MANUFACTURER_HOOK);
+        List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
+        for (ResolveInfo resolveInfo : list) {
+            if (resolveInfo.activityInfo.packageName.equals(PACKAGE_NAME)) {
+                result = true;
+            }
+        }
+        assertTrue("Intent-filer not found", result);
+    }
+
+    /**
+     * Test that the operator preference is available in the Settings
+     * application.
+     */
+    public void testOperatorPreferenceAvailable() {
+        PreferenceGroup root = (PreferenceGroup)mSettings.findPreference(KEY_SETTINGS_ROOT);
+        Preference operatorPreference = root.findPreference(KEY_SETTINGS_OPERATOR);
+        assertNotNull(operatorPreference);
+    }
+
+    /**
+     * Test that the manufacturer preference is available in the Settings
+     * application.
+     */
+    public void testManufacturerPreferenceAvailable() {
+        PreferenceGroup root = (PreferenceGroup)mSettings.findPreference(KEY_SETTINGS_ROOT);
+        Preference manufacturerHook = root.findPreference(KEY_SETTINGS_MANUFACTURER);
+        assertNotNull(manufacturerHook);
+    }
+
+}
diff --git a/tests/src/com/android/settings/tests/Manufacturer.java b/tests/src/com/android/settings/tests/Manufacturer.java
new file mode 100644 (file)
index 0000000..692e6a8
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.tests;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Manufacturer extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.manufacturer_main);
+    }
+}
diff --git a/tests/src/com/android/settings/tests/Operator.java b/tests/src/com/android/settings/tests/Operator.java
new file mode 100644 (file)
index 0000000..8a34363
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.tests;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Operator extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.operator_main);
+    }
+
+}