Merge change 8186 into donut

* changes:
  Move global search intent launching to search dialog
This commit is contained in:
Android (Google) Code Review
2009-07-22 12:14:58 -07:00

View File

@ -34,7 +34,10 @@ import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Browser;
import android.server.search.SearchableInfo;
import android.speech.RecognizerIntent;
import android.text.Editable;
@ -42,6 +45,7 @@ import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.util.Regex;
import android.util.AndroidRuntimeException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextThemeWrapper;
@ -1093,7 +1097,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
*/
protected void launchQuerySearch(int actionKey, String actionMsg) {
String query = mSearchAutoComplete.getText().toString();
Intent intent = createIntent(Intent.ACTION_SEARCH, null, null, query, null,
String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
Intent intent = createIntent(action, null, null, query, null,
actionKey, actionMsg);
launchIntent(intent);
}
@ -1245,14 +1250,125 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
return;
}
Log.d(LOG_TAG, "launching " + intent);
try {
// in global search mode, we send the activity straight to the original suggestion
// source. this is because GlobalSearch may not have permission to launch the
// intent, and to avoid the extra step of going through GlobalSearch.
if (mGlobalSearchMode) {
launchGlobalSearchIntent(intent);
} else {
getContext().startActivity(intent);
// in global search mode, SearchDialogWrapper#performActivityResuming will handle hiding
// the dialog when the next activity starts, but for in-app search, we still need to
// dismiss the dialog.
if (!mGlobalSearchMode) {
// in global search mode, SearchDialogWrapper#performActivityResuming
// will handle hiding the dialog when the next activity starts, but for
// in-app search, we still need to dismiss the dialog.
dismiss();
}
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "Failed launch activity: " + intent, ex);
}
}
private void launchGlobalSearchIntent(Intent intent) {
final String packageName;
// GlobalSearch puts the original source of the suggestion in the
// 'component name' column. If set, we send the intent to that activity.
// We trust GlobalSearch to always set this to the suggestion source.
String intentComponent = intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY);
if (intentComponent != null) {
ComponentName componentName = ComponentName.unflattenFromString(intentComponent);
intent.setComponent(componentName);
intent.removeExtra(SearchManager.COMPONENT_NAME_KEY);
// Launch the intent as the suggestion source.
// This prevents sources from using the search dialog to launch
// intents that they don't have permission for themselves.
packageName = componentName.getPackageName();
} else {
// If there is no component in the suggestion, it must be a built-in suggestion
// from GlobalSearch (e.g. "Search the web for") or the intent
// launched when pressing the search/go button in the search dialog.
// Launch the intent with the permissions of GlobalSearch.
packageName = mSearchable.getSearchActivity().getPackageName();
}
// Launch all global search suggestions as new tasks, since they don't relate
// to the current task.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
setBrowserApplicationId(intent);
if (DBG) Log.d(LOG_TAG, "Launching intent " + intent.toURI() + " as " + packageName);
startActivityInPackage(intent, packageName);
}
/**
* If the intent is to open an HTTP or HTTPS URL, we set
* {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that
* has been opened by us for the same URL will be reused.
*/
private void setBrowserApplicationId(Intent intent) {
Uri data = intent.getData();
if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null) {
String scheme = data.getScheme();
if (scheme != null && scheme.startsWith("http")) {
intent.putExtra(Browser.EXTRA_APPLICATION_ID, data.toString());
}
}
}
/**
* Starts an activity as if it had been started by the given package.
*
* @param intent The description of the activity to start.
* @param packageName
* @throws ActivityNotFoundException If the intent could not be resolved to
* and existing activity.
* @throws SecurityException If the package does not have permission to start
* start the activity.
* @throws AndroidRuntimeException If some other error occurs.
*/
private void startActivityInPackage(Intent intent, String packageName) {
try {
int uid = ActivityThread.getPackageManager().getPackageUid(packageName);
if (uid < 0) {
throw new AndroidRuntimeException("Package UID not found " + packageName);
}
String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
IBinder resultTo = null;
String resultWho = null;
int requestCode = -1;
boolean onlyIfNeeded = false;
int result = ActivityManagerNative.getDefault().startActivityInPackage(
uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded);
checkStartActivityResult(result, intent);
} catch (RemoteException ex) {
throw new AndroidRuntimeException(ex);
}
}
// Stolen from Instrumentation.checkStartActivityResult()
private static void checkStartActivityResult(int res, Intent intent) {
if (res >= IActivityManager.START_SUCCESS) {
return;
}
switch (res) {
case IActivityManager.START_INTENT_NOT_RESOLVED:
case IActivityManager.START_CLASS_NOT_FOUND:
if (intent.getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ intent.getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case IActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
/**
@ -1460,8 +1576,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
intent.putExtra(SearchManager.ACTION_KEY, actionKey);
intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
}
// attempt to enforce security requirement (no 3rd-party intents)
// Only allow 3rd-party intents from GlobalSearch
if (!mGlobalSearchMode) {
intent.setComponent(mSearchable.getSearchActivity());
}
return intent;
}