Merge change 6507 into donut
* changes:
Remove unused definitions for default language in TextToSpeech as the default language is determined by the current Locale, not a hardcoded value. Add a value for the default TTS engine to use.
diff --git a/api/current.xml b/api/current.xml
index 9bce1f3..d97a0f4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2275,6 +2275,17 @@
visibility="public"
>
</field>
+<field name="autoUrlDetect"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843404"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="background"
type="int"
transient="false"
@@ -3386,28 +3397,6 @@
visibility="public"
>
</field>
-<field name="donut_resource_pad20"
- type="int"
- transient="false"
- volatile="false"
- value="16843404"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="donut_resource_pad21"
- type="int"
- transient="false"
- volatile="false"
- value="16843403"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="donut_resource_pad3"
type="int"
transient="false"
@@ -8413,6 +8402,17 @@
visibility="public"
>
</field>
+<field name="textColorPrimaryInverseDisableOnly"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843403"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="textColorPrimaryInverseNoDisable"
type="int"
transient="false"
diff --git a/awt/Android.mk b/awt/Android.mk
index c7480f5..213c6ce 100644
--- a/awt/Android.mk
+++ b/awt/Android.mk
@@ -28,4 +28,4 @@
LOCAL_DX_FLAGS := --core-library
-include $(BUILD_JAVA_LIBRARY)
+#include $(BUILD_JAVA_LIBRARY)
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ca9632a..6c2560d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -606,7 +606,6 @@
private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
- private static final String SAVED_SEARCH_DIALOG_KEY = "android:search_dialog";
private SparseArray<Dialog> mManagedDialogs;
@@ -630,7 +629,6 @@
/*package*/ int mConfigChangeFlags;
/*package*/ Configuration mCurrentConfig;
private SearchManager mSearchManager;
- private Bundle mSearchDialogState = null;
private Window mWindow;
@@ -808,13 +806,6 @@
final void performRestoreInstanceState(Bundle savedInstanceState) {
onRestoreInstanceState(savedInstanceState);
restoreManagedDialogs(savedInstanceState);
-
- // Also restore the state of a search dialog (if any)
- // TODO more generic than just this manager
- Bundle searchState = savedInstanceState.getBundle(SAVED_SEARCH_DIALOG_KEY);
- if (searchState != null) {
- mSearchManager.restoreSearchDialog(searchState);
- }
}
/**
@@ -866,7 +857,7 @@
if (dialogState != null) {
// Calling onRestoreInstanceState() below will invoke dispatchOnCreate
// so tell createDialog() not to do it, otherwise we get an exception
- final Dialog dialog = createDialog(dialogId, false);
+ final Dialog dialog = createDialog(dialogId, dialogState);
mManagedDialogs.put(dialogId, dialog);
onPrepareDialog(dialogId, dialog);
dialog.onRestoreInstanceState(dialogState);
@@ -874,13 +865,13 @@
}
}
- private Dialog createDialog(Integer dialogId, boolean dispatchOnCreate) {
+ private Dialog createDialog(Integer dialogId, Bundle state) {
final Dialog dialog = onCreateDialog(dialogId);
if (dialog == null) {
throw new IllegalArgumentException("Activity#onCreateDialog did "
+ "not create a dialog for id " + dialogId);
}
- if (dispatchOnCreate) dialog.dispatchOnCreate(null);
+ dialog.dispatchOnCreate(state);
return dialog;
}
@@ -1030,14 +1021,6 @@
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
-
- // Also save the state of a search dialog (if any)
- // TODO more generic than just this manager
- // onPause() should always be called before this method, so mSearchManagerState
- // should be up to date.
- if (mSearchDialogState != null) {
- outState.putBundle(SAVED_SEARCH_DIALOG_KEY, mSearchDialogState);
- }
}
/**
@@ -1317,10 +1300,6 @@
c.mCursor.close();
}
}
-
- // Clear any search state saved in performPause(). If the state may be needed in the
- // future, it will have been saved by performSaveInstanceState()
- mSearchDialogState = null;
}
/**
@@ -1341,11 +1320,7 @@
*/
public void onConfigurationChanged(Configuration newConfig) {
mCalled = true;
-
- // also update search dialog if showing
- // TODO more generic than just this manager
- mSearchManager.onConfigurationChanged(newConfig);
-
+
if (mWindow != null) {
// Pass the configuration changed event to the window
mWindow.onConfigurationChanged(newConfig);
@@ -2432,7 +2407,7 @@
}
Dialog dialog = mManagedDialogs.get(id);
if (dialog == null) {
- dialog = createDialog(id, true);
+ dialog = createDialog(id, null);
mManagedDialogs.put(id, dialog);
}
@@ -3575,20 +3550,12 @@
"Activity " + mComponent.toShortString() +
" did not call through to super.onPostResume()");
}
-
- // restore search dialog, if any
- if (mSearchDialogState != null) {
- mSearchManager.restoreSearchDialog(mSearchDialogState);
- }
- mSearchDialogState = null;
}
final void performPause() {
onPause();
- // save search dialog state if the search dialog is open,
- // and then dismiss the search dialog
- mSearchDialogState = mSearchManager.saveSearchDialog();
+ // dismiss the search dialog if it is open
mSearchManager.stopSearch();
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 222fe75..2b165fc 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -292,8 +292,10 @@
// internal method to make sure mcreated is set properly without requiring
// users to call through to super in onCreate
void dispatchOnCreate(Bundle savedInstanceState) {
- onCreate(savedInstanceState);
- mCreated = true;
+ if (!mCreated) {
+ onCreate(savedInstanceState);
+ mCreated = true;
+ }
}
/**
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index e8bd60a..5b62192 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -36,8 +36,4 @@
boolean globalSearch,
ISearchManagerCallback searchManagerCallback);
void stopSearch();
- boolean isVisible();
- Bundle onSaveInstanceState();
- void onRestoreInstanceState(in Bundle savedInstanceState);
- void onConfigurationChanged(in Configuration newConfig);
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index fdb619a..022a9d9 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -19,13 +19,11 @@
import static android.app.SuggestionsAdapter.getColumnString;
import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -33,8 +31,8 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
@@ -95,11 +93,7 @@
private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12;
private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7;
-
- // interaction with runtime
- private IntentFilter mCloseDialogsFilter;
- private IntentFilter mPackageFilter;
-
+
// views & widgets
private TextView mBadgeLabel;
private ImageView mAppIcon;
@@ -210,15 +204,7 @@
// Touching outside of the search dialog will dismiss it
setCanceledOnTouchOutside(true);
-
- // Set up broadcast filters
- mCloseDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mPackageFilter = new IntentFilter();
- mPackageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- mPackageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- mPackageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- mPackageFilter.addDataScheme("package");
-
+
// Save voice intent for later queries/launching
mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -382,15 +368,6 @@
return true;
}
-
- @Override
- protected void onStart() {
- super.onStart();
-
- // receive broadcasts
- getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter);
- getContext().registerReceiver(mBroadcastReceiver, mPackageFilter);
- }
/**
* The search dialog is being dismissed, so handle all of the local shutdown operations.
@@ -401,14 +378,7 @@
@Override
public void onStop() {
super.onStop();
-
- // stop receiving broadcasts (throws exception if none registered)
- try {
- getContext().unregisterReceiver(mBroadcastReceiver);
- } catch (RuntimeException e) {
- // This is OK - it just means we didn't have any registered
- }
-
+
closeSuggestionsAdapter();
// dump extra memory we're hanging on to
@@ -455,12 +425,15 @@
/**
* Save the minimal set of data necessary to recreate the search
*
- * @return A bundle with the state of the dialog.
+ * @return A bundle with the state of the dialog, or {@code null} if the search
+ * dialog is not showing.
*/
@Override
public Bundle onSaveInstanceState() {
+ if (!isShowing()) return null;
+
Bundle bundle = new Bundle();
-
+
// setup info so I can recreate this particular search
bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent);
bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData);
@@ -483,6 +456,8 @@
*/
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
+ if (savedInstanceState == null) return;
+
ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
boolean globalSearch = savedInstanceState.getBoolean(INSTANCE_KEY_GLOBALSEARCH);
@@ -509,7 +484,7 @@
/**
* Called after resources have changed, e.g. after screen rotation or locale change.
*/
- public void onConfigurationChanged(Configuration newConfig) {
+ public void onConfigurationChanged() {
if (isShowing()) {
// Redraw (resources may have changed)
updateSearchButton();
@@ -777,7 +752,7 @@
}
public void afterTextChanged(Editable s) {
- if (!mSearchAutoComplete.isPerformingCompletion()) {
+ if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) {
// The user changed the query, check if it is a URL and if so change the search
// button in the soft keyboard to the 'Go' button.
int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION));
@@ -987,17 +962,19 @@
&& event.getAction() == KeyEvent.ACTION_UP) {
v.cancelLongPress();
- // If this is a url entered by the user and we displayed the 'Go' button which
- // the user clicked, launch the url instead of using it as a search query.
- if ((mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION)
- == EditorInfo.IME_ACTION_GO) {
- Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString()));
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- launchIntent(intent);
- } else {
- // Launch as a regular search.
- launchQuerySearch();
+ if (mSearchable.autoUrlDetect()) {
+ // If this is a url entered by the user & we displayed the 'Go' button which
+ // the user clicked, launch the url instead of using it as a search query.
+ if ((mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION)
+ == EditorInfo.IME_ACTION_GO) {
+ Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString()));
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ launchIntent(intent);
+ } else {
+ // Launch as a regular search.
+ launchQuerySearch();
+ }
}
return true;
}
@@ -1012,35 +989,11 @@
return false;
}
};
-
- /**
- * When the ACTION_CLOSE_SYSTEM_DIALOGS intent is received, we should close ourselves
- * immediately, in order to allow a higher-priority UI to take over
- * (e.g. phone call received).
- *
- * When a package is added, removed or changed, our current context
- * may no longer be valid. This would only happen if a package is installed/removed exactly
- * when the search bar is open. So for now we're just going to close the search
- * bar.
- * Anything fancier would require some checks to see if the user's context was still valid.
- * Which would be messier.
- */
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- cancel();
- } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)
- || Intent.ACTION_PACKAGE_REMOVED.equals(action)
- || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- cancel();
- }
- }
- };
@Override
public void cancel() {
+ if (!isShowing()) return;
+
// We made sure the IME was displayed, so also make sure it is closed
// when we go away.
InputMethodManager imm = (InputMethodManager)getContext()
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index e5ba6a4..5d25f10 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -20,7 +20,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -1730,59 +1729,6 @@
}
/**
- * Saves the state of the search UI.
- *
- * @return A Bundle containing the state of the search dialog, or {@code null}
- * if the search UI is not visible.
- *
- * @hide
- */
- public Bundle saveSearchDialog() {
- if (DBG) debug("saveSearchDialog(), mIsShowing=" + mIsShowing);
- if (!mIsShowing) return null;
- try {
- return mService.onSaveInstanceState();
- } catch (RemoteException ex) {
- Log.e(TAG, "onSaveInstanceState() failed: " + ex);
- return null;
- }
- }
-
- /**
- * Restores the state of the search dialog.
- *
- * @param searchDialogState Bundle to read the state from.
- *
- * @hide
- */
- public void restoreSearchDialog(Bundle searchDialogState) {
- if (DBG) debug("restoreSearchDialog(" + searchDialogState + ")");
- if (searchDialogState == null) return;
- try {
- mService.onRestoreInstanceState(searchDialogState);
- } catch (RemoteException ex) {
- Log.e(TAG, "onRestoreInstanceState() failed: " + ex);
- }
- }
-
- /**
- * Update the search dialog after a configuration change.
- *
- * @param newConfig The new configuration.
- *
- * @hide
- */
- public void onConfigurationChanged(Configuration newConfig) {
- if (DBG) debug("onConfigurationChanged(" + newConfig + "), mIsShowing=" + mIsShowing);
- if (!mIsShowing) return;
- try {
- mService.onConfigurationChanged(newConfig);
- } catch (RemoteException ex) {
- Log.e(TAG, "onConfigurationChanged() failed:" + ex);
- }
- }
-
- /**
* Gets information about a searchable activity. This method is static so that it can
* be used from non-Activity contexts.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0d27e1e..aa583ac 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1359,8 +1359,21 @@
SCREEN_BRIGHTNESS,
VIBRATE_ON,
NOTIFICATIONS_USE_RING_VOLUME,
- RINGTONE,
- NOTIFICATION_SOUND,
+ MODE_RINGER,
+ MODE_RINGER_STREAMS_AFFECTED,
+ MUTE_STREAMS_AFFECTED,
+ VOLUME_VOICE,
+ VOLUME_SYSTEM,
+ VOLUME_RING,
+ VOLUME_MUSIC,
+ VOLUME_ALARM,
+ VOLUME_NOTIFICATION,
+ VOLUME_VOICE + APPEND_FOR_LAST_AUDIBLE,
+ VOLUME_SYSTEM + APPEND_FOR_LAST_AUDIBLE,
+ VOLUME_RING + APPEND_FOR_LAST_AUDIBLE,
+ VOLUME_MUSIC + APPEND_FOR_LAST_AUDIBLE,
+ VOLUME_ALARM + APPEND_FOR_LAST_AUDIBLE,
+ VOLUME_NOTIFICATION + APPEND_FOR_LAST_AUDIBLE,
TEXT_AUTO_REPLACE,
TEXT_AUTO_CAPS,
TEXT_AUTO_PUNCTUATE,
@@ -2299,6 +2312,8 @@
* @hide
*/
public static final String[] SETTINGS_TO_BACKUP = {
+ ADB_ENABLED,
+ ALLOW_MOCK_LOCATION,
INSTALL_NON_MARKET_APPS,
PARENTAL_CONTROL_ENABLED,
PARENTAL_CONTROL_REDIRECT_URL,
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
new file mode 100644
index 0000000..dbc1e7f
--- /dev/null
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2007 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 android.server.search;
+
+import android.app.ISearchManagerCallback;
+import android.app.SearchDialog;
+import android.app.SearchManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Runs an instance of {@link SearchDialog} on its own thread.
+ */
+class SearchDialogWrapper
+implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
+
+ private static final String TAG = "SearchManagerService";
+ private static final boolean DBG = false;
+
+ private static final String DISABLE_SEARCH_PROPERTY = "dev.disablesearchdialog";
+
+ private static final String SEARCH_UI_THREAD_NAME = "SearchDialog";
+ private static final int SEARCH_UI_THREAD_PRIORITY =
+ android.os.Process.THREAD_PRIORITY_FOREGROUND;
+
+ // Takes no arguments
+ private static final int MSG_INIT = 0;
+ // Takes these arguments:
+ // arg1: selectInitialQuery, 0 = false, 1 = true
+ // arg2: globalSearch, 0 = false, 1 = true
+ // obj: searchManagerCallback
+ // data[KEY_INITIAL_QUERY]: initial query
+ // data[KEY_LAUNCH_ACTIVITY]: launch activity
+ // data[KEY_APP_SEARCH_DATA]: app search data
+ private static final int MSG_START_SEARCH = 1;
+ // Takes no arguments
+ private static final int MSG_STOP_SEARCH = 2;
+ // Takes no arguments
+ private static final int MSG_ON_CONFIGURATION_CHANGED = 3;
+
+ private static final String KEY_INITIAL_QUERY = "q";
+ private static final String KEY_LAUNCH_ACTIVITY = "a";
+ private static final String KEY_APP_SEARCH_DATA = "d";
+
+ // Context used for getting search UI resources
+ private final Context mContext;
+
+ // Handles messages on the search UI thread.
+ private final SearchDialogHandler mSearchUiThread;
+
+ // The search UI
+ SearchDialog mSearchDialog;
+
+ // If the search UI is visible, this is the callback for the client that showed it.
+ ISearchManagerCallback mCallback = null;
+
+ // Allows disabling of search dialog for stress testing runs
+ private final boolean mDisabledOnBoot;
+
+ /**
+ * Creates a new search dialog wrapper and a search UI thread. The search dialog itself will
+ * be created some asynchronously on the search UI thread.
+ *
+ * @param context Context used for getting search UI resources.
+ */
+ public SearchDialogWrapper(Context context) {
+ mContext = context;
+
+ mDisabledOnBoot = !TextUtils.isEmpty(SystemProperties.get(DISABLE_SEARCH_PROPERTY));
+
+ // Create the search UI thread
+ HandlerThread t = new HandlerThread(SEARCH_UI_THREAD_NAME, SEARCH_UI_THREAD_PRIORITY);
+ t.start();
+ mSearchUiThread = new SearchDialogHandler(t.getLooper());
+
+ // Create search UI on the search UI thread
+ mSearchUiThread.sendEmptyMessage(MSG_INIT);
+ }
+
+ /**
+ * Initializes the search UI.
+ * Must be called from the search UI thread.
+ */
+ private void init() {
+ mSearchDialog = new SearchDialog(mContext);
+ mSearchDialog.setOnCancelListener(this);
+ mSearchDialog.setOnDismissListener(this);
+ }
+
+ private void registerBroadcastReceiver() {
+ IntentFilter closeDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ mContext.registerReceiver(mBroadcastReceiver, closeDialogsFilter);
+ IntentFilter configurationChangedFilter =
+ new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
+ mContext.registerReceiver(mBroadcastReceiver, configurationChangedFilter);
+ }
+
+ private void unregisterBroadcastReceiver() {
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ }
+
+ /**
+ * Closes the search dialog when requested by the system (e.g. when a phone call comes in).
+ */
+ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+ if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ stopSearch();
+ } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+ if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED);
+ onConfigurationChanged();
+ }
+ }
+ };
+
+ //
+ // External API
+ //
+
+ /**
+ * Launches the search UI.
+ * Can be called from any thread.
+ *
+ * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
+ */
+ public void startSearch(final String initialQuery,
+ final boolean selectInitialQuery,
+ final ComponentName launchActivity,
+ final Bundle appSearchData,
+ final boolean globalSearch,
+ final ISearchManagerCallback searchManagerCallback) {
+ if (DBG) debug("startSearch()");
+ Message msg = Message.obtain();
+ msg.what = MSG_START_SEARCH;
+ msg.arg1 = selectInitialQuery ? 1 : 0;
+ msg.arg2 = globalSearch ? 1 : 0;
+ msg.obj = searchManagerCallback;
+ Bundle msgData = msg.getData();
+ msgData.putString(KEY_INITIAL_QUERY, initialQuery);
+ msgData.putParcelable(KEY_LAUNCH_ACTIVITY, launchActivity);
+ msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData);
+ mSearchUiThread.sendMessage(msg);
+ }
+
+ /**
+ * Cancels the search dialog.
+ * Can be called from any thread.
+ */
+ public void stopSearch() {
+ if (DBG) debug("stopSearch()");
+ mSearchUiThread.sendEmptyMessage(MSG_STOP_SEARCH);
+ }
+
+ /**
+ * Updates the search UI in response to a configuration change.
+ * Can be called from any thread.
+ */
+ void onConfigurationChanged() {
+ if (DBG) debug("onConfigurationChanged()");
+ mSearchUiThread.sendEmptyMessage(MSG_ON_CONFIGURATION_CHANGED);
+ }
+
+ //
+ // Implementation methods that run on the search UI thread
+ //
+
+ private class SearchDialogHandler extends Handler {
+
+ public SearchDialogHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_INIT:
+ init();
+ break;
+ case MSG_START_SEARCH:
+ handleStartSearchMessage(msg);
+ break;
+ case MSG_STOP_SEARCH:
+ performStopSearch();
+ break;
+ case MSG_ON_CONFIGURATION_CHANGED:
+ performOnConfigurationChanged();
+ break;
+ }
+ }
+
+ private void handleStartSearchMessage(Message msg) {
+ Bundle msgData = msg.getData();
+ String initialQuery = msgData.getString(KEY_INITIAL_QUERY);
+ boolean selectInitialQuery = msg.arg1 != 0;
+ ComponentName launchActivity =
+ (ComponentName) msgData.getParcelable(KEY_LAUNCH_ACTIVITY);
+ Bundle appSearchData = msgData.getBundle(KEY_APP_SEARCH_DATA);
+ boolean globalSearch = msg.arg2 != 0;
+ ISearchManagerCallback searchManagerCallback = (ISearchManagerCallback) msg.obj;
+ performStartSearch(initialQuery, selectInitialQuery, launchActivity,
+ appSearchData, globalSearch, searchManagerCallback);
+ }
+
+ }
+
+ /**
+ * Actually launches the search UI.
+ * This must be called on the search UI thread.
+ */
+ void performStartSearch(String initialQuery,
+ boolean selectInitialQuery,
+ ComponentName launchActivity,
+ Bundle appSearchData,
+ boolean globalSearch,
+ ISearchManagerCallback searchManagerCallback) {
+ if (DBG) debug("performStartSearch()");
+
+ if (mDisabledOnBoot) {
+ Log.d(TAG, "ignoring start search request because " + DISABLE_SEARCH_PROPERTY
+ + " system property is set.");
+ return;
+ }
+
+ registerBroadcastReceiver();
+ mCallback = searchManagerCallback;
+ mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
+ globalSearch);
+ }
+
+ /**
+ * Actually cancels the search UI.
+ * This must be called on the search UI thread.
+ */
+ void performStopSearch() {
+ if (DBG) debug("performStopSearch()");
+ mSearchDialog.cancel();
+ }
+
+ /**
+ * Must be called from the search UI thread.
+ */
+ void performOnConfigurationChanged() {
+ if (DBG) debug("performOnConfigurationChanged()");
+ mSearchDialog.onConfigurationChanged();
+ }
+
+ /**
+ * Called by {@link SearchDialog} when it goes away.
+ */
+ public void onDismiss(DialogInterface dialog) {
+ if (DBG) debug("onDismiss()");
+ if (mCallback != null) {
+ try {
+ // should be safe to do on the search UI thread, since it's a oneway interface
+ mCallback.onDismiss();
+ } catch (DeadObjectException ex) {
+ // The process that hosted the callback has died, do nothing
+ } catch (RemoteException ex) {
+ Log.e(TAG, "onDismiss() failed: " + ex);
+ }
+ // we don't need the callback anymore, release it
+ mCallback = null;
+ }
+ unregisterBroadcastReceiver();
+ }
+
+ /**
+ * Called by {@link SearchDialog} when the user or activity cancels search.
+ * Whenever this method is called, {@link #onDismiss} is always called afterwards.
+ */
+ public void onCancel(DialogInterface dialog) {
+ if (DBG) debug("onCancel()");
+ if (mCallback != null) {
+ try {
+ // should be safe to do on the search UI thread, since it's a oneway interface
+ mCallback.onCancel();
+ } catch (DeadObjectException ex) {
+ // The process that hosted the callback has died, do nothing
+ } catch (RemoteException ex) {
+ Log.e(TAG, "onCancel() failed: " + ex);
+ }
+ }
+ }
+
+ private static void debug(String msg) {
+ Thread thread = Thread.currentThread();
+ Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
+ }
+}
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index 373e61f..87adfb3 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -18,52 +18,38 @@
import android.app.ISearchManager;
import android.app.ISearchManagerCallback;
-import android.app.SearchDialog;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.text.TextUtils;
import android.util.Log;
import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
/**
- * This is a simplified version of the Search Manager service. It no longer handles
- * presentation (UI). Its function is to maintain the map & list of "searchable"
- * items, which provides a mapping from individual activities (where a user might have
- * invoked search) to specific searchable activities (where the search will be dispatched).
+ * The search manager service handles the search UI, and maintains a registry of searchable
+ * activities.
*/
-public class SearchManagerService extends ISearchManager.Stub
- implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener
-{
- // general debugging support
+public class SearchManagerService extends ISearchManager.Stub {
+
+ // general debugging support
private static final String TAG = "SearchManagerService";
private static final boolean DBG = false;
- // class maintenance and general shared data
+ // Context that the service is running in.
private final Context mContext;
- private final Handler mHandler;
- private boolean mSearchablesDirty;
- private final Searchables mSearchables;
- final SearchDialog mSearchDialog;
- ISearchManagerCallback mCallback = null;
+ // This field is initialized in initialize(), and then never modified.
+ // It is volatile since it can be accessed by multiple threads.
+ private volatile Searchables mSearchables;
- private final boolean mDisabledOnBoot;
-
- private static final String DISABLE_SEARCH_PROPERTY = "dev.disablesearchdialog";
+ // This field is initialized in initialize(), and then never modified.
+ // It is volatile since it can be accessed by multiple threads.
+ private volatile SearchDialogWrapper mSearchDialog;
/**
* Initializes the Search Manager service in the provided system context.
@@ -73,82 +59,71 @@
*/
public SearchManagerService(Context context) {
mContext = context;
- mHandler = new Handler();
- mSearchablesDirty = true;
- mSearchables = new Searchables(context);
- mSearchDialog = new SearchDialog(context);
- mSearchDialog.setOnCancelListener(this);
- mSearchDialog.setOnDismissListener(this);
-
- // Setup the infrastructure for updating and maintaining the list
- // of searchable activities.
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
-
- // After startup settles down, preload the searchables list,
- // which will reduce the delay when the search UI is invoked.
- mHandler.post(mRunUpdateSearchable);
-
- // allows disabling of search dialog for stress testing runs
- mDisabledOnBoot = !TextUtils.isEmpty(SystemProperties.get(DISABLE_SEARCH_PROPERTY));
+ // call initialize() after all pending actions on the main system thread have finished
+ new Handler().post(new Runnable() {
+ public void run() {
+ initialize();
+ }
+ });
}
/**
- * Listens for intent broadcasts.
- *
- * The primary purpose here is to refresh the "searchables" list
- * if packages are added/removed.
+ * Initializes the search UI and the list of searchable activities.
*/
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ void initialize() {
+ mSearchables = createSearchables();
+ mSearchDialog = new SearchDialogWrapper(mContext);
+ }
+
+ private Searchables createSearchables() {
+ Searchables searchables = new Searchables(mContext);
+ searchables.buildSearchableList();
+
+ IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilter.addDataScheme("package");
+ mContext.registerReceiver(mPackageChangedReceiver, packageFilter);
+
+ return searchables;
+ }
+
+ /**
+ * Refreshes the "searchables" list when packages are added/removed.
+ */
+ private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- // First, test for intents that matter at any time
- if (action.equals(Intent.ACTION_PACKAGE_ADDED) ||
- action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
- action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
- mSearchablesDirty = true;
- mHandler.post(mRunUpdateSearchable);
- return;
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+ Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
+ Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ if (DBG) Log.d(TAG, "Got " + action);
+ // Dismiss search dialog, since the search context may no longer be valid
+ mSearchDialog.stopSearch();
+ // Update list of searchable activities
+ mSearchables.buildSearchableList();
+ broadcastSearchablesChanged();
}
}
};
/**
- * This runnable (for the main handler / UI thread) will update the searchables list.
+ * Informs all listeners that the list of searchables has been updated.
*/
- private Runnable mRunUpdateSearchable = new Runnable() {
- public void run() {
- updateSearchablesIfDirty();
- }
- };
-
- /**
- * Updates the list of searchables, either at startup or in response to
- * a package add/remove broadcast message.
- */
- private void updateSearchables() {
- if (DBG) debug("updateSearchables()");
- mSearchables.buildSearchableList();
- mSearchablesDirty = false;
+ void broadcastSearchablesChanged() {
+ mContext.sendBroadcast(
+ new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED));
}
- /**
- * Updates the list of searchables if needed.
- */
- private void updateSearchablesIfDirty() {
- if (mSearchablesDirty) {
- updateSearchables();
- }
- }
+ //
+ // Searchable activities API
+ //
/**
- * Returns the SearchableInfo for a given activity
+ * Returns the SearchableInfo for a given activity.
*
* @param launchActivity The activity from which we're launching this search.
* @param globalSearch If false, this will only launch the search that has been specifically
@@ -158,226 +133,84 @@
* @return Returns a SearchableInfo record describing the parameters of the search,
* or null if no searchable metadata was available.
*/
- public SearchableInfo getSearchableInfo(ComponentName launchActivity, boolean globalSearch) {
- updateSearchablesIfDirty();
- SearchableInfo si = null;
+ public SearchableInfo getSearchableInfo(final ComponentName launchActivity,
+ final boolean globalSearch) {
+ if (mSearchables == null) return null;
if (globalSearch) {
- si = mSearchables.getDefaultSearchable();
+ return mSearchables.getDefaultSearchable();
} else {
if (launchActivity == null) {
Log.e(TAG, "getSearchableInfo(), activity == null");
return null;
}
- si = mSearchables.getSearchableInfo(launchActivity);
+ return mSearchables.getSearchableInfo(launchActivity);
}
-
- return si;
}
/**
* Returns a list of the searchable activities that can be included in global search.
*/
public List<SearchableInfo> getSearchablesInGlobalSearch() {
- updateSearchablesIfDirty();
+ if (mSearchables == null) return null;
return mSearchables.getSearchablesInGlobalSearchList();
}
- /**
- * Launches the search UI on the main thread of the service.
- *
- * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
- */
- public void startSearch(final String initialQuery,
- final boolean selectInitialQuery,
- final ComponentName launchActivity,
- final Bundle appSearchData,
- final boolean globalSearch,
- final ISearchManagerCallback searchManagerCallback) {
- if (DBG) debug("startSearch()");
- Runnable task = new Runnable() {
- public void run() {
- performStartSearch(initialQuery,
- selectInitialQuery,
- launchActivity,
- appSearchData,
- globalSearch,
- searchManagerCallback);
- }
- };
- mHandler.post(task);
- }
/**
- * Actually launches the search. This must be called on the service UI thread.
+ * Returns a list of the searchable activities that handle web searches.
+ * Can be called from any thread.
*/
- /*package*/ void performStartSearch(String initialQuery,
+ public List<SearchableInfo> getSearchablesForWebSearch() {
+ if (mSearchables == null) return null;
+ return mSearchables.getSearchablesForWebSearchList();
+ }
+
+ /**
+ * Returns the default searchable activity for web searches.
+ * Can be called from any thread.
+ */
+ public SearchableInfo getDefaultSearchableForWebSearch() {
+ if (mSearchables == null) return null;
+ return mSearchables.getDefaultSearchableForWebSearch();
+ }
+
+ /**
+ * Sets the default searchable activity for web searches.
+ * Can be called from any thread.
+ */
+ public void setDefaultWebSearch(final ComponentName component) {
+ if (mSearchables == null) return;
+ mSearchables.setDefaultWebSearch(component);
+ broadcastSearchablesChanged();
+ }
+
+ // Search UI API
+
+ /**
+ * Launches the search UI. Can be called from any thread.
+ *
+ * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
+ */
+ public void startSearch(String initialQuery,
boolean selectInitialQuery,
ComponentName launchActivity,
Bundle appSearchData,
boolean globalSearch,
ISearchManagerCallback searchManagerCallback) {
- if (DBG) debug("performStartSearch()");
-
- if (mDisabledOnBoot) {
- Log.d(TAG, "ignoring start search request because " + DISABLE_SEARCH_PROPERTY
- + " system property is set.");
- return;
- }
-
- mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
- globalSearch);
- if (searchManagerCallback != null) {
- mCallback = searchManagerCallback;
- }
+ if (mSearchDialog == null) return;
+ mSearchDialog.startSearch(initialQuery,
+ selectInitialQuery,
+ launchActivity,
+ appSearchData,
+ globalSearch,
+ searchManagerCallback);
}
/**
* Cancels the search dialog. Can be called from any thread.
*/
public void stopSearch() {
- if (DBG) debug("stopSearch()");
- mHandler.post(new Runnable() {
- public void run() {
- performStopSearch();
- }
- });
- }
-
- /**
- * Cancels the search dialog. Must be called from the service UI thread.
- */
- /*package*/ void performStopSearch() {
- if (DBG) debug("performStopSearch()");
- mSearchDialog.cancel();
- }
-
- /**
- * Determines if the Search UI is currently displayed.
- *
- * @see SearchManager#isVisible()
- */
- public boolean isVisible() {
- return postAndWait(mIsShowing, false, "isShowing()");
- }
-
- private final Callable<Boolean> mIsShowing = new Callable<Boolean>() {
- public Boolean call() {
- return mSearchDialog.isShowing();
- }
- };
-
- public Bundle onSaveInstanceState() {
- return postAndWait(mOnSaveInstanceState, null, "onSaveInstanceState()");
- }
-
- private final Callable<Bundle> mOnSaveInstanceState = new Callable<Bundle>() {
- public Bundle call() {
- if (mSearchDialog.isShowing()) {
- return mSearchDialog.onSaveInstanceState();
- } else {
- return null;
- }
- }
- };
-
- public void onRestoreInstanceState(final Bundle searchDialogState) {
- if (searchDialogState != null) {
- mHandler.post(new Runnable() {
- public void run() {
- mSearchDialog.onRestoreInstanceState(searchDialogState);
- }
- });
- }
- }
-
- public void onConfigurationChanged(final Configuration newConfig) {
- mHandler.post(new Runnable() {
- public void run() {
- if (mSearchDialog.isShowing()) {
- mSearchDialog.onConfigurationChanged(newConfig);
- }
- }
- });
- }
-
- /**
- * Called by {@link SearchDialog} when it goes away.
- */
- public void onDismiss(DialogInterface dialog) {
- if (DBG) debug("onDismiss()");
- if (mCallback != null) {
- try {
- mCallback.onDismiss();
- } catch (RemoteException ex) {
- Log.e(TAG, "onDismiss() failed: " + ex);
- }
- }
- }
-
- /**
- * Called by {@link SearchDialog} when the user or activity cancels search.
- * When this is called, {@link #onDismiss} is called too.
- */
- public void onCancel(DialogInterface dialog) {
- if (DBG) debug("onCancel()");
- if (mCallback != null) {
- try {
- mCallback.onCancel();
- } catch (RemoteException ex) {
- Log.e(TAG, "onCancel() failed: " + ex);
- }
- }
- }
-
- /**
- * Returns a list of the searchable activities that handle web searches.
- */
- public List<SearchableInfo> getSearchablesForWebSearch() {
- updateSearchablesIfDirty();
- return mSearchables.getSearchablesForWebSearchList();
- }
-
- /**
- * Returns the default searchable activity for web searches.
- */
- public SearchableInfo getDefaultSearchableForWebSearch() {
- updateSearchablesIfDirty();
- return mSearchables.getDefaultSearchableForWebSearch();
- }
-
- /**
- * Sets the default searchable activity for web searches.
- */
- public void setDefaultWebSearch(ComponentName component) {
- mSearchables.setDefaultWebSearch(component);
- }
-
- /**
- * Runs an operation on the handler for the service, blocks until it returns,
- * and returns the value returned by the operation.
- *
- * @param <V> Return value type.
- * @param callable Operation to run.
- * @param errorResult Value to return if the operations throws an exception.
- * @param name Operation name to include in error log messages.
- * @return The value returned by the operation.
- */
- private <V> V postAndWait(Callable<V> callable, V errorResult, String name) {
- FutureTask<V> task = new FutureTask<V>(callable);
- mHandler.post(task);
- try {
- return task.get();
- } catch (InterruptedException ex) {
- Log.e(TAG, "Error calling " + name + ": " + ex);
- return errorResult;
- } catch (ExecutionException ex) {
- Log.e(TAG, "Error calling " + name + ": " + ex);
- return errorResult;
- }
- }
-
- private static void debug(String msg) {
- Thread thread = Thread.currentThread();
- Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
+ if (mSearchDialog == null) return;
+ mSearchDialog.stopSearch();
}
}
diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java
index 8ef1f15..283555a 100644
--- a/core/java/android/server/search/SearchableInfo.java
+++ b/core/java/android/server/search/SearchableInfo.java
@@ -67,6 +67,7 @@
private final int mSearchImeOptions;
private final boolean mIncludeInGlobalSearch;
private final boolean mQueryAfterZeroResults;
+ private final boolean mAutoUrlDetect;
private final String mSettingsDescription;
private final String mSuggestAuthority;
private final String mSuggestPath;
@@ -288,6 +289,8 @@
com.android.internal.R.styleable.Searchable_includeInGlobalSearch, false);
mQueryAfterZeroResults = a.getBoolean(
com.android.internal.R.styleable.Searchable_queryAfterZeroResults, false);
+ mAutoUrlDetect = a.getBoolean(
+ com.android.internal.R.styleable.Searchable_autoUrlDetect, false);
mSettingsDescription = a.getString(
com.android.internal.R.styleable.Searchable_searchSettingsDescription);
@@ -667,6 +670,16 @@
}
/**
+ * Checks whether this searchable activity has auto URL detect turned on.
+ *
+ * @return The value of the <code>autoUrlDetect</code> attribute,
+ * or <code>false</code> if the attribute is not set.
+ */
+ public boolean autoUrlDetect() {
+ return mAutoUrlDetect;
+ }
+
+ /**
* Support for parcelable and aidl operations.
*/
public static final Parcelable.Creator<SearchableInfo> CREATOR
@@ -698,6 +711,7 @@
mSearchImeOptions = in.readInt();
mIncludeInGlobalSearch = in.readInt() != 0;
mQueryAfterZeroResults = in.readInt() != 0;
+ mAutoUrlDetect = in.readInt() != 0;
mSettingsDescription = in.readString();
mSuggestAuthority = in.readString();
@@ -735,6 +749,7 @@
dest.writeInt(mSearchImeOptions);
dest.writeInt(mIncludeInGlobalSearch ? 1 : 0);
dest.writeInt(mQueryAfterZeroResults ? 1 : 0);
+ dest.writeInt(mAutoUrlDetect ? 1 : 0);
dest.writeString(mSettingsDescription);
dest.writeString(mSuggestAuthority);
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index c7cc8ed..b959907 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -17,7 +17,6 @@
package android.server.search;
import com.android.internal.app.ResolverActivity;
-import com.android.internal.R;
import android.app.SearchManager;
import android.content.ComponentName;
@@ -27,7 +26,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
@@ -264,7 +262,7 @@
}
// Find the default web search provider.
- ComponentName webSearchActivity = getPreferredWebSearchActivity();
+ ComponentName webSearchActivity = getPreferredWebSearchActivity(mContext);
SearchableInfo newDefaultSearchableForWebSearch = null;
if (webSearchActivity != null) {
newDefaultSearchableForWebSearch = newSearchablesMap.get(webSearchActivity);
@@ -283,9 +281,6 @@
mDefaultSearchable = newDefaultSearchable;
mDefaultSearchableForWebSearch = newDefaultSearchableForWebSearch;
}
-
- // Inform all listeners that the list of searchables has been updated.
- mContext.sendBroadcast(new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED));
}
/**
@@ -295,9 +290,10 @@
* @param action Intent action for which this activity is to be set as preferred.
* @return true if component was detected and set as preferred activity, false if not.
*/
- private boolean setPreferredActivity(ComponentName component, String action) {
+ private static boolean setPreferredActivity(Context context,
+ ComponentName component, String action) {
Log.d(LOG_TAG, "Checking component " + component);
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = context.getPackageManager();
ActivityInfo ai;
try {
ai = pm.getActivityInfo(component, 0);
@@ -326,10 +322,10 @@
return true;
}
- public ComponentName getPreferredWebSearchActivity() {
+ private static ComponentName getPreferredWebSearchActivity(Context context) {
// Check if we have a preferred web search activity.
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = context.getPackageManager();
ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (ri == null || ri.activityInfo.name.equals(ResolverActivity.class.getName())) {
@@ -338,11 +334,11 @@
// The components in the providers array are checked in the order of declaration so the
// first one has the highest priority. If the component exists in the system it is set
// as the preferred activity to handle intent action web search.
- String[] preferredActivities = mContext.getResources().getStringArray(
+ String[] preferredActivities = context.getResources().getStringArray(
com.android.internal.R.array.default_web_search_providers);
for (String componentName : preferredActivities) {
ComponentName component = ComponentName.unflattenFromString(componentName);
- if (setPreferredActivity(component, Intent.ACTION_WEB_SEARCH)) {
+ if (setPreferredActivity(context, component, Intent.ACTION_WEB_SEARCH)) {
return component;
}
}
@@ -354,7 +350,8 @@
if (cn.flattenToShortString().equals(GOOGLE_SEARCH_COMPONENT_NAME)) {
ComponentName enhancedGoogleSearch = ComponentName.unflattenFromString(
ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME);
- if (setPreferredActivity(enhancedGoogleSearch, Intent.ACTION_WEB_SEARCH)) {
+ if (setPreferredActivity(context, enhancedGoogleSearch,
+ Intent.ACTION_WEB_SEARCH)) {
return enhancedGoogleSearch;
}
}
@@ -397,7 +394,7 @@
* Sets the default searchable activity for web searches.
*/
public synchronized void setDefaultWebSearch(ComponentName component) {
- setPreferredActivity(component, Intent.ACTION_WEB_SEARCH);
+ setPreferredActivity(mContext, component, Intent.ACTION_WEB_SEARCH);
buildSearchableList();
}
}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 670692f..df957ac 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -65,6 +65,7 @@
*/
public static final int LENGTH_LONG = 1;
+ final Handler mHandler = new Handler();
final Context mContext;
final TN mTN;
int mDuration;
@@ -84,7 +85,7 @@
*/
public Toast(Context context) {
mContext = context;
- mTN = new TN(context);
+ mTN = new TN();
mY = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.toast_y_offset);
}
@@ -229,7 +230,8 @@
public static Toast makeText(Context context, CharSequence text, int duration) {
Toast result = new Toast(context);
- LayoutInflater inflate = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflate = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
tv.setText(text);
@@ -286,8 +288,7 @@
private static INotificationManager sService;
- static private INotificationManager getService()
- {
+ static private INotificationManager getService() {
if (sService != null) {
return sService;
}
@@ -295,28 +296,42 @@
return sService;
}
- private class TN extends ITransientNotification.Stub
- {
- TN(Context context)
- {
+ private class TN extends ITransientNotification.Stub {
+ final Runnable mShow = new Runnable() {
+ public void run() {
+ handleShow();
+ }
+ };
+
+ final Runnable mHide = new Runnable() {
+ public void run() {
+ handleHide();
+ }
+ };
+
+ private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+
+ WindowManagerImpl mWM;
+
+ TN() {
// XXX This should be changed to use a Dialog, with a Theme.Toast
// defined that sets up the layout params appropriately.
- mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
- mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
- mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ final WindowManager.LayoutParams params = mParams;
+ params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+ params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
- mParams.format = PixelFormat.TRANSLUCENT;
- mParams.windowAnimations = com.android.internal.R.style.Animation_Toast;
- mParams.type = WindowManager.LayoutParams.TYPE_TOAST;
- mParams.setTitle("Toast");
+ params.format = PixelFormat.TRANSLUCENT;
+ params.windowAnimations = com.android.internal.R.style.Animation_Toast;
+ params.type = WindowManager.LayoutParams.TYPE_TOAST;
+ params.setTitle("Toast");
}
/**
* schedule handleShow into the right thread
*/
- public void show()
- {
+ public void show() {
if (localLOGV) Log.v(TAG, "SHOW: " + this);
mHandler.post(mShow);
}
@@ -324,14 +339,12 @@
/**
* schedule handleHide into the right thread
*/
- public void hide()
- {
+ public void hide() {
if (localLOGV) Log.v(TAG, "HIDE: " + this);
mHandler.post(mHide);
}
- public void handleShow()
- {
+ public void handleShow() {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
if (mView != mNextView) {
@@ -361,8 +374,7 @@
}
}
- public void handleHide()
- {
+ public void handleHide() {
if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
if (mView != null) {
// note: checking parent() just to make sure the view has
@@ -377,24 +389,5 @@
mView = null;
}
}
-
- Runnable mShow = new Runnable() {
- public void run() {
- handleShow();
- }
- };
-
- Runnable mHide = new Runnable() {
- public void run() {
- handleHide();
- }
- };
-
- private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-
- WindowManagerImpl mWM;
}
-
- final Handler mHandler = new Handler();
}
-
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 10308b6..fd78f83 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -68,6 +68,9 @@
<!-- Bright text color. Only differentiates based on the disabled state. -->
<attr name="textColorPrimaryDisableOnly" format="reference|color" />
+ <!-- Bright inverse text color. Only differentiates based on the disabled state. -->
+ <attr name="textColorPrimaryInverseDisableOnly" format="reference|color" />
+
<!-- Bright text color. This does not differentiate the disabled state. As an example,
buttons use this since they display the disabled state via the background and not the
foreground text color. -->
@@ -2885,6 +2888,14 @@
attribute.</i> -->
<attr name="searchSettingsDescription" format="string" />
+ <!-- If provided and <code>true</code>, URLs entered in the search dialog while searching
+ within this activity would be detected and treated as URLs (show a 'go' button in the
+ keyboard and invoke the browser directly when user launches the URL instead of passing
+ the URL to the activity). If set to <code>false</code> any URLs entered are treated as
+ normal query text.
+ The default value is <code>false</code>. <i>Optional attribute.</i>. -->
+ <attr name="autoUrlDetect" format="boolean" />
+
</declare-styleable>
<!-- In order to process special action keys during search, you must define them using
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 148935f..871c651 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1124,6 +1124,8 @@
<public type="attr" name="progressBarStyleSmallInverse" />
<public type="attr" name="progressBarStyleLargeInverse" />
<public type="attr" name="searchSettingsDescription" />
+ <public type="attr" name="textColorPrimaryInverseDisableOnly" />
+ <public type="attr" name="autoUrlDetect" />
<public-padding type="attr" name="donut_resource_pad" end="0x0101029f" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bd6e1df..be836eb 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -44,6 +44,7 @@
<item name="textColorSecondaryInverse">@android:color/secondary_text_light</item>
<item name="textColorTertiaryInverse">@android:color/tertiary_text_light</item>
<item name="textColorPrimaryDisableOnly">@android:color/primary_text_dark_disable_only</item>
+ <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_light_disable_only</item>
<item name="textColorPrimaryNoDisable">@android:color/primary_text_dark_nodisable</item>
<item name="textColorSecondaryNoDisable">@android:color/secondary_text_dark_nodisable</item>
<item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_light_nodisable</item>
@@ -220,6 +221,7 @@
<item name="textColorSecondaryInverse">@android:color/secondary_text_dark</item>
<item name="textColorTertiaryInverse">@android:color/tertiary_text_dark</item>
<item name="textColorPrimaryDisableOnly">@android:color/primary_text_light_disable_only</item>
+ <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_dark_disable_only</item>
<item name="textColorPrimaryNoDisable">@android:color/primary_text_light_nodisable</item>
<item name="textColorSecondaryNoDisable">@android:color/secondary_text_light_nodisable</item>
<item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_dark_nodisable</item>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0bd3276..a3579c7 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -143,8 +143,6 @@
<!-- This is a list of all the libraries available for application
code to link against. -->
- <library name="android.awt"
- file="/system/framework/android.awt.jar" />
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
<library name="com.android.im.plugin"
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index d24194f..6677a35 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -278,10 +278,15 @@
if (name.equals("padding")) {
TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.ShapeDrawablePadding);
- setPadding(a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_left, 0),
- a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_top, 0),
- a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_right, 0),
- a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_bottom, 0));
+ setPadding(
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.ShapeDrawablePadding_left, 0),
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.ShapeDrawablePadding_top, 0),
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.ShapeDrawablePadding_right, 0),
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.ShapeDrawablePadding_bottom, 0));
a.recycle();
return true;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index cfdf5e3..a65a417 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1063,6 +1063,21 @@
}
}
+ /**
+ * @hide
+ * Reload audio settings. This method is called by Settings backup
+ * agent when audio settings are restored and causes the AudioService
+ * to read and apply restored settings.
+ */
+ public void reloadAudioSettings() {
+ IAudioService service = getService();
+ try {
+ service.reloadAudioSettings();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in reloadAudioSettings"+e);
+ }
+ }
+
/**
* {@hide}
*/
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 937baad..ee41021 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -508,14 +508,14 @@
/** @see AudioManager#setRingerMode(int) */
public void setRingerMode(int ringerMode) {
if (ringerMode != mRingerMode) {
- setRingerModeInt(ringerMode);
+ setRingerModeInt(ringerMode, true);
// Send sticky broadcast
broadcastRingerMode();
}
}
- private void setRingerModeInt(int ringerMode) {
+ private void setRingerModeInt(int ringerMode, boolean persist) {
mRingerMode = ringerMode;
// Adjust volumes via posting message
@@ -543,8 +543,10 @@
}
// Post a persist ringer mode msg
- sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
- SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
+ if (persist) {
+ sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
+ SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
+ }
}
/** @see AudioManager#shouldVibrate(int) */
@@ -914,6 +916,46 @@
}
}
+ /** @see AudioManager#reloadAudioSettings() */
+ public void reloadAudioSettings() {
+ // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
+ readPersistedSettings();
+
+ // restore volume settings
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+ VolumeStreamState streamState = mStreamStates[streamType];
+
+ // there is no volume setting for STREAM_BLUETOOTH_SCO
+ if (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {
+ String settingName = System.VOLUME_SETTINGS[streamType];
+ String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+
+ streamState.mIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
+ settingName,
+ AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
+ streamState.mLastAudibleIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
+ lastAudibleSettingName,
+ streamState.mIndex > 0 ? streamState.mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
+ }
+ // unmute stream that whas muted but is not affect by mute anymore
+ if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
+ int size = streamState.mDeathHandlers.size();
+ for (int i = 0; i < size; i++) {
+ streamState.mDeathHandlers.get(i).mMuteCount = 1;
+ streamState.mDeathHandlers.get(i).mute(false);
+ }
+ }
+ // apply stream volume
+ if (streamState.muteCount() == 0) {
+ AudioSystem.setVolume(streamType, streamState.mVolumes[streamState.mIndex]);
+ }
+ }
+
+ // apply new ringer mode
+ setRingerModeInt(getRingerMode(), false);
+ }
+
///////////////////////////////////////////////////////////////////////////
// Internal methods
///////////////////////////////////////////////////////////////////////////
@@ -1426,7 +1468,7 @@
* Ensure all stream types that should be affected by ringer mode
* are in the proper state.
*/
- setRingerModeInt(getRingerMode());
+ setRingerModeInt(getRingerMode(), false);
}
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index f5e242d..9a8264f 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -71,4 +71,5 @@
oneway void unloadSoundEffects();
+ oneway void reloadAudioSettings();
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index f9e98ef..b6bc8a5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -50,6 +50,7 @@
private static final String KEY_SYSTEM = "system";
private static final String KEY_SECURE = "secure";
private static final String KEY_SYNC = "sync_providers";
+ private static final String KEY_LOCALE = "locale";
private static String[] sortedSystemKeys = null;
private static String[] sortedSecureKeys = null;
@@ -85,6 +86,7 @@
byte[] systemSettingsData = getSystemSettings();
byte[] secureSettingsData = getSecureSettings();
byte[] syncProviders = mSettingsHelper.getSyncProviders();
+ byte[] locale = mSettingsHelper.getLocaleData();
data.writeEntityHeader(KEY_SYSTEM, systemSettingsData.length);
data.writeEntityData(systemSettingsData, systemSettingsData.length);
@@ -94,7 +96,10 @@
data.writeEntityHeader(KEY_SYNC, syncProviders.length);
data.writeEntityData(syncProviders, syncProviders.length);
-
+
+ data.writeEntityHeader(KEY_LOCALE, locale.length);
+ data.writeEntityData(locale, locale.length);
+
backupFile(FILE_WIFI_SUPPLICANT, data);
}
@@ -107,14 +112,20 @@
while (data.readNextHeader()) {
final String key = data.getKey();
+ final int size = data.getDataSize();
if (KEY_SYSTEM.equals(key)) {
restoreSettings(data, Settings.System.CONTENT_URI);
} else if (KEY_SECURE.equals(key)) {
restoreSettings(data, Settings.Secure.CONTENT_URI);
- } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
- restoreFile(FILE_WIFI_SUPPLICANT, data);
+// TODO: Re-enable WIFI restore when we figure out a solution for the permissions
+// } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
+// restoreFile(FILE_WIFI_SUPPLICANT, data);
} else if (KEY_SYNC.equals(key)) {
mSettingsHelper.setSyncProviders(data);
+ } else if (KEY_LOCALE.equals(key)) {
+ byte[] localeData = new byte[size];
+ data.readEntityData(localeData, 0, size);
+ mSettingsHelper.setLocaleData(localeData);
} else {
data.skipEntityData();
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 5f3fba8..2c5775a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -16,16 +16,22 @@
package com.android.providers.settings;
+import java.util.Locale;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
import android.backup.BackupDataInput;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentService;
+import android.content.res.Configuration;
import android.location.LocationManager;
import android.media.AudioManager;
import android.os.IHardwareService;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
public class SettingsHelper {
@@ -110,7 +116,6 @@
}
}
- /* TODO: Get a list of all sync providers and save/restore the settings */
byte[] getSyncProviders() {
byte[] sync = new byte[1 + PROVIDERS.length];
try {
@@ -141,4 +146,53 @@
Log.w(TAG, "Unable to read sync settings");
}
}
+
+ byte[] getLocaleData() {
+ Configuration conf = mContext.getResources().getConfiguration();
+ final Locale loc = conf.locale;
+ String localeString = loc.getLanguage();
+ String country = loc.getCountry();
+ if (!TextUtils.isEmpty(country)) {
+ localeString += "_" + country;
+ }
+ return localeString.getBytes();
+ }
+
+ /**
+ * Sets the locale specified. Input data is the equivalent of "ll_cc".getBytes(), where
+ * "ll" is the language code and "cc" is the country code.
+ * @param data the locale string in bytes.
+ */
+ void setLocaleData(byte[] data) {
+ // Check if locale was set by the user:
+ Configuration conf = mContext.getResources().getConfiguration();
+ Locale loc = conf.locale;
+ if (conf.userSetLocale) return; // Don't change if user set it in the SetupWizard
+
+ final String[] availableLocales = mContext.getAssets().getLocales();
+ String localeCode = new String(data);
+ String language = new String(data, 0, 2);
+ String country = data.length > 4 ? new String(data, 3, 2) : "";
+ loc = null;
+ for (int i = 0; i < availableLocales.length; i++) {
+ if (availableLocales[i].equals(localeCode)) {
+ loc = new Locale(language, country);
+ break;
+ }
+ }
+ if (loc == null) return; // Couldn't find the saved locale in this version of the software
+
+ try {
+ IActivityManager am = ActivityManagerNative.getDefault();
+ Configuration config = am.getConfiguration();
+ config.locale = loc;
+ // indicate this isn't some passing default - the user wants this remembered
+ config.userSetLocale = true;
+
+ am.updateConfiguration(config);
+ } catch (RemoteException e) {
+ // Intentionally left blank
+ }
+
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a21bf32..2abf8b3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -18,7 +18,7 @@
import java.io.FileNotFoundException;
-import android.backup.IBackupManager;
+import android.backup.BackupManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -46,6 +46,8 @@
private static final String TABLE_OLD_FAVORITES = "old_favorites";
private DatabaseHelper mOpenHelper;
+
+ private BackupManager mBackupManager;
/**
* Decode a content URL into the table, projection, and arguments
@@ -140,16 +142,7 @@
}
// Inform the backup manager about a data change
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (ibm != null) {
- try {
- ibm.dataChanged(getContext().getPackageName());
- } catch (Exception e) {
- // Try again later
- }
- }
-
+ mBackupManager.dataChanged();
// Now send the notification through the content framework.
String notify = uri.getQueryParameter("notify");
@@ -189,6 +182,7 @@
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
+ mBackupManager = new BackupManager(getContext());
return true;
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 3b82284..6e28515 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -810,17 +810,25 @@
// Now propagate the newly-backed-up data to the transport
if (success) {
- if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
- backupData =
- ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
- if (!transport.performBackup(packInfo, backupData)) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in performBackup()");
+ if (DEBUG) Log.v(TAG, "doBackup() success");
+ if (backupDataName.length() > 0) {
+ backupData =
+ ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ if (!transport.performBackup(packInfo, backupData)) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in performBackup()");
+ }
+ } else {
+ if (DEBUG) {
+ Log.i(TAG, "no backup data written; not calling transport");
+ }
}
- // !!! TODO: After successful transport, delete the now-stale data
- // and juggle the files so that next time the new state is passed
- //backupDataName.delete();
+ // After successful transport, delete the now-stale data
+ // and juggle the files so that next time we supply the agent
+ // with the new state file it just created.
+ backupDataName.delete();
newStateName.renameTo(savedStateName);
}
} catch (Exception e) {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java b/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java
new file mode 100644
index 0000000..2bdf1dd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.unit_tests;
+
+import android.test.AndroidTestCase;
+import android.telephony.NeighboringCellInfo;
+import android.test. suitebuilder.annotation.SmallTest;
+
+public class NeighboringCellInfoTest extends AndroidTestCase {
+ @SmallTest
+ public void testConstructor() {
+ NeighboringCellInfo empty = new NeighboringCellInfo();
+ assertEquals(NeighboringCellInfo.UNKNOWN_RSSI, empty.getRssi());
+ assertEquals(NeighboringCellInfo.UNKNOWN_CID, empty.getCid());
+
+ int rssi = 31;
+ int cid = 0xffffffff;
+ NeighboringCellInfo max = new NeighboringCellInfo(rssi, cid);
+ assertEquals(rssi, max.getRssi());
+ assertEquals(cid, max.getCid());
+ }
+
+ @SmallTest
+ public void testGetAndSet() {
+ int rssi = 16;
+ int cid = 0x12345678;
+ NeighboringCellInfo nc = new NeighboringCellInfo();
+ nc.setRssi(rssi);
+ nc.setCid(cid);
+ assertEquals(rssi, nc.getRssi());
+ assertEquals(cid, nc.getCid());
+ }
+
+ @SmallTest
+ public void testToString() {
+ NeighboringCellInfo empty = new NeighboringCellInfo();
+ assertEquals("[/ at /]", empty.toString());
+
+ NeighboringCellInfo nc = new NeighboringCellInfo(16, 0x12345678);
+ assertEquals("[12345678 at 16]", nc.toString());
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
index c4f1ab6..4c5fefc 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
@@ -107,8 +107,6 @@
}
// Checks that the search UI is not visible.
- // This checks both the SearchManager and the SearchManagerService,
- // since SearchManager keeps a local variable for the visibility.
private void assertSearchNotVisible() {
SearchManager searchManager = (SearchManager)
mContext.getSystemService(Context.SEARCH_SERVICE);
@@ -245,22 +243,4 @@
assertSearchNotVisible();
}
- @MediumTest
- public void testSearchDialogState() throws Exception {
- SearchManager searchManager = (SearchManager)
- mContext.getSystemService(Context.SEARCH_SERVICE);
- assertNotNull(searchManager);
-
- Bundle searchState;
-
- // search dialog not visible, so no state should be stored
- searchState = searchManager.saveSearchDialog();
- assertNull(searchState);
-
- searchManager.startSearch("test search string", true, SEARCHABLE_ACTIVITY, null, false);
- searchState = searchManager.saveSearchDialog();
- assertNotNull(searchState);
- searchManager.stopSearch();
- }
-
}