diff options
Diffstat (limited to 'core')
21 files changed, 606 insertions, 704 deletions
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 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper /*package*/ int mConfigChangeFlags; /*package*/ Configuration mCurrentConfig; private SearchManager mSearchManager; - private Bundle mSearchDialogState = null; private Window mWindow; @@ -808,13 +806,6 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper } } - 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 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper 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 class Activity extends ContextThemeWrapper */ 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 @@ public class Activity extends ContextThemeWrapper } Dialog dialog = mManagedDialogs.get(id); if (dialog == null) { - dialog = createDialog(id, true); + dialog = createDialog(id, null); mManagedDialogs.put(id, dialog); } @@ -3575,20 +3550,12 @@ public class Activity extends ContextThemeWrapper "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 @@ public class Dialog implements DialogInterface, Window.Callback, // 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 @@ interface ISearchManager { 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 @@ package android.app; 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.pm.PackageManager.NameNotFoundException; 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS @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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS /** * 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ @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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS /** * 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 class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS && 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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.ComponentName; 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 @@ public class SearchManager } /** - * 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/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index bcf95b6..0d00f21 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -173,7 +173,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@hide} */ public static final int ANY_DENSITY = -1; - private static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY }; + static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY }; /** * Flags associated with the application. Any combination of diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 558b0c3..b293636 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -945,15 +945,25 @@ public class PackageParser { >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; } - + int densities[] = null; int size = pkg.supportsDensityList.size(); if (size > 0) { - int densities[] = pkg.supportsDensities = new int[size]; + densities = pkg.supportsDensities = new int[size]; List<Integer> densityList = pkg.supportsDensityList; for (int i = 0; i < size; i++) { densities[i] = densityList.get(i); } } + /** + * TODO: enable this before code freeze. b/1967935 + * * + if ((densities == null || densities.length == 0) + && (pkg.applicationInfo.targetSdkVersion + >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { + pkg.supportsDensities = ApplicationInfo.ANY_DENSITIES_ARRAY; + } + */ + return pkg; } diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index dfe304d..ebe556e 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -51,18 +51,6 @@ public class CompatibilityInfo { public static final int DEFAULT_PORTRAIT_HEIGHT = 480; /** - * The x-shift mode that controls the position of the content or the window under - * compatibility mode. - * {@see getTranslator} - * {@see Translator#mShiftMode} - */ - private static final int X_SHIFT_NONE = 0; - private static final int X_SHIFT_CONTENT = 1; - private static final int X_SHIFT_AND_CLIP_CONTENT = 2; - private static final int X_SHIFT_WINDOW = 3; - - - /** * A compatibility flags */ private int mCompatibilityFlags; @@ -106,20 +94,6 @@ public class CompatibilityInfo { */ public final int appFlags; - /** - * Window size in Compatibility Mode, in real pixels. This is updated by - * {@link DisplayMetrics#updateMetrics}. - */ - private int mWidth; - private int mHeight; - - /** - * The x offset to center the window content. In X_SHIFT_WINDOW mode, the offset is added - * to the window's layout. In X_SHIFT_CONTENT/X_SHIFT_AND_CLIP_CONTENT mode, the offset - * is used to translate the Canvas. - */ - private int mXOffset; - public CompatibilityInfo(ApplicationInfo appInfo) { appFlags = appInfo.flags; @@ -153,6 +127,7 @@ public class CompatibilityInfo { applicationScale = DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY; } + applicationInvertedScale = 1.0f / applicationScale; if (applicationScale != 1.0f) { mCompatibilityFlags |= SCALING_REQUIRED; @@ -181,23 +156,10 @@ public class CompatibilityInfo { public CompatibilityInfo copy() { CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags, applicationScale, applicationInvertedScale); - info.setVisibleRect(mXOffset, mWidth, mHeight); return info; } /** - * Sets the application's visible rect in compatibility mode. - * @param xOffset the application's x offset that is added to center the content. - * @param widthPixels the application's width in real pixels on the screen. - * @param heightPixels the application's height in real pixels on the screen. - */ - public void setVisibleRect(int xOffset, int widthPixels, int heightPixels) { - this.mXOffset = xOffset; - mWidth = widthPixels; - mHeight = heightPixels; - } - - /** * Sets expandable bit in the compatibility flag. */ public void setExpandable(boolean expandable) { @@ -222,6 +184,10 @@ public class CompatibilityInfo { return (mCompatibilityFlags & SCALING_REQUIRED) != 0; } + public boolean supportsScreen() { + return (mCompatibilityFlags & CompatibilityInfo.EXPANDABLE) != 0; + } + @Override public String toString() { return "CompatibilityInfo{scale=" + applicationScale + @@ -231,21 +197,6 @@ public class CompatibilityInfo { /** * Returns the translator which can translate the coordinates of the window. * There are five different types of Translator. - * - * 1) {@link CompatibilityInfo#X_SHIFT_AND_CLIP_CONTENT} - * Shift and clip the content of the window at drawing time. Used for activities' - * main window (with no gravity). - * 2) {@link CompatibilityInfo#X_SHIFT_CONTENT} - * Shift the content of the window at drawing time. Used for windows that is created by - * an application and expected to be aligned with the application window. - * 3) {@link CompatibilityInfo#X_SHIFT_WINDOW} - * Create the window with adjusted x- coordinates. This is typically used - * in popup window, where it has to be placed relative to main window. - * 4) {@link CompatibilityInfo#X_SHIFT_NONE} - * No adjustment required, such as dialog. - * 5) Same as X_SHIFT_WINDOW, but no scaling. This is used by {@link SurfaceView}, which - * does not require scaling, but its window's location has to be adjusted. - * * @param params the window's parameter */ public Translator getTranslator(WindowManager.LayoutParams params) { @@ -254,35 +205,11 @@ public class CompatibilityInfo { if (DBG) Log.d(TAG, "no translation required"); return null; } - - if ((mCompatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) { - if ((params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) { - if (DBG) Log.d(TAG, "translation for surface view selected"); - return new Translator(X_SHIFT_WINDOW, false, 1.0f, 1.0f); - } else { - int shiftMode; - if (params.gravity == Gravity.NO_GRAVITY) { - // For Regular Application window - shiftMode = X_SHIFT_AND_CLIP_CONTENT; - if (DBG) Log.d(TAG, "shift and clip translator"); - } else if (params.width == WindowManager.LayoutParams.FILL_PARENT) { - // For Regular Application window - shiftMode = X_SHIFT_CONTENT; - if (DBG) Log.d(TAG, "shift content translator"); - } else if ((params.gravity & Gravity.LEFT) != 0 && params.x > 0) { - shiftMode = X_SHIFT_WINDOW; - if (DBG) Log.d(TAG, "shift window translator"); - } else { - shiftMode = X_SHIFT_NONE; - if (DBG) Log.d(TAG, "no content/window translator"); - } - return new Translator(shiftMode); - } - } else if (isScalingRequired()) { - return new Translator(); - } else { + if (!isScalingRequired() || + (params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) { return null; } + return new Translator(); } /** @@ -290,97 +217,48 @@ public class CompatibilityInfo { * @hide */ public class Translator { - final private int mShiftMode; - final public boolean scalingRequired; final public float applicationScale; final public float applicationInvertedScale; private Rect mContentInsetsBuffer = null; - private Rect mVisibleInsets = null; + private Rect mVisibleInsetsBuffer = null; - Translator(int shiftMode, boolean scalingRequired, float applicationScale, - float applicationInvertedScale) { - mShiftMode = shiftMode; - this.scalingRequired = scalingRequired; + Translator(float applicationScale, float applicationInvertedScale) { this.applicationScale = applicationScale; this.applicationInvertedScale = applicationInvertedScale; } - Translator(int shiftMode) { - this(shiftMode, - isScalingRequired(), - CompatibilityInfo.this.applicationScale, - CompatibilityInfo.this.applicationInvertedScale); - } - Translator() { - this(X_SHIFT_NONE); + this(CompatibilityInfo.this.applicationScale, + CompatibilityInfo.this.applicationInvertedScale); } /** * Translate the screen rect to the application frame. */ public void translateRectInScreenToAppWinFrame(Rect rect) { - if (rect.isEmpty()) return; // skip if the window size is empty. - switch (mShiftMode) { - case X_SHIFT_AND_CLIP_CONTENT: - rect.intersect(0, 0, mWidth, mHeight); - break; - case X_SHIFT_CONTENT: - rect.intersect(0, 0, mWidth + mXOffset, mHeight); - break; - case X_SHIFT_WINDOW: - case X_SHIFT_NONE: - break; - } - if (scalingRequired) { - rect.scale(applicationInvertedScale); - } + rect.scale(applicationInvertedScale); } /** * Translate the region in window to screen. */ public void translateRegionInWindowToScreen(Region transparentRegion) { - switch (mShiftMode) { - case X_SHIFT_AND_CLIP_CONTENT: - case X_SHIFT_CONTENT: - transparentRegion.scale(applicationScale); - transparentRegion.translate(mXOffset, 0); - break; - case X_SHIFT_WINDOW: - case X_SHIFT_NONE: - transparentRegion.scale(applicationScale); - } + transparentRegion.scale(applicationScale); } /** * Apply translation to the canvas that is necessary to draw the content. */ public void translateCanvas(Canvas canvas) { - if (mShiftMode == X_SHIFT_CONTENT || - mShiftMode == X_SHIFT_AND_CLIP_CONTENT) { - // TODO: clear outside when rotation is changed. - - // Translate x-offset only when the content is shifted. - canvas.translate(mXOffset, 0); - } - if (scalingRequired) { - canvas.scale(applicationScale, applicationScale); - } + canvas.scale(applicationScale, applicationScale); } /** * Translate the motion event captured on screen to the application's window. */ public void translateEventInScreenToAppWindow(MotionEvent event) { - if (mShiftMode == X_SHIFT_CONTENT || - mShiftMode == X_SHIFT_AND_CLIP_CONTENT) { - event.translate(-mXOffset, 0); - } - if (scalingRequired) { - event.scale(applicationInvertedScale); - } + event.scale(applicationInvertedScale); } /** @@ -388,62 +266,21 @@ public class CompatibilityInfo { * Screen's view. */ public void translateWindowLayout(WindowManager.LayoutParams params) { - switch (mShiftMode) { - case X_SHIFT_NONE: - case X_SHIFT_AND_CLIP_CONTENT: - case X_SHIFT_CONTENT: - params.scale(applicationScale); - break; - case X_SHIFT_WINDOW: - params.scale(applicationScale); - params.x += mXOffset; - break; - } + params.scale(applicationScale); } /** * Translate a Rect in application's window to screen. */ public void translateRectInAppWindowToScreen(Rect rect) { - // TODO Auto-generated method stub - if (scalingRequired) { - rect.scale(applicationScale); - } - switch(mShiftMode) { - case X_SHIFT_NONE: - case X_SHIFT_WINDOW: - break; - case X_SHIFT_CONTENT: - case X_SHIFT_AND_CLIP_CONTENT: - rect.offset(mXOffset, 0); - break; - } + rect.scale(applicationScale); } /** * Translate a Rect in screen coordinates into the app window's coordinates. */ public void translateRectInScreenToAppWindow(Rect rect) { - switch (mShiftMode) { - case X_SHIFT_NONE: - case X_SHIFT_WINDOW: - break; - case X_SHIFT_CONTENT: { - rect.intersects(mXOffset, 0, rect.right, rect.bottom); - int dx = Math.min(mXOffset, rect.left); - rect.offset(-dx, 0); - break; - } - case X_SHIFT_AND_CLIP_CONTENT: { - rect.intersects(mXOffset, 0, mWidth + mXOffset, mHeight); - int dx = Math.min(mXOffset, rect.left); - rect.offset(-dx, 0); - break; - } - } - if (scalingRequired) { - rect.scale(applicationInvertedScale); - } + rect.scale(applicationInvertedScale); } /** @@ -451,19 +288,7 @@ public class CompatibilityInfo { * @param params */ public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) { - if (scalingRequired) { - params.scale(applicationScale); - } - switch (mShiftMode) { - // the window location on these mode does not require adjustmenet. - case X_SHIFT_NONE: - case X_SHIFT_WINDOW: - break; - case X_SHIFT_CONTENT: - case X_SHIFT_AND_CLIP_CONTENT: - params.x += mXOffset; - break; - } + params.scale(applicationScale); } /** @@ -482,10 +307,31 @@ public class CompatibilityInfo { * the internal buffer for content insets to avoid extra object allocation. */ public Rect getTranslatedVisbileInsets(Rect visibleInsets) { - if (mVisibleInsets == null) mVisibleInsets = new Rect(); - mVisibleInsets.set(visibleInsets); - translateRectInAppWindowToScreen(mVisibleInsets); - return mVisibleInsets; + if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect(); + mVisibleInsetsBuffer.set(visibleInsets); + translateRectInAppWindowToScreen(mVisibleInsetsBuffer); + return mVisibleInsetsBuffer; + } + } + + /** + * Returns the frame Rect for applications runs under compatibility mode. + * + * @param dm the display metrics used to compute the frame size. + * @param orientation the orientation of the screen. + * @param outRect the output parameter which will contain the result. + */ + public static void updateCompatibleScreenFrame(DisplayMetrics dm, int orientation, + Rect outRect) { + int width = dm.widthPixels; + int portraitHeight = (int) (DEFAULT_PORTRAIT_HEIGHT * dm.density); + int portraitWidth = (int) (DEFAULT_PORTRAIT_WIDTH * dm.density); + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + int xOffset = (width - portraitHeight) / 2 ; + outRect.set(xOffset, 0, xOffset + portraitHeight, portraitWidth); + } else { + int xOffset = (width - portraitWidth) / 2 ; + outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight); } } } 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 @@ package android.server.search; 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; - private final boolean mDisabledOnBoot; + // 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 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 class SearchManagerService extends ISearchManager.Stub */ 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); + // call initialize() after all pending actions on the main system thread have finished + new Handler().post(new Runnable() { + public void run() { + initialize(); + } + }); + } - // 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); + /** + * Initializes the search UI and the list of searchable activities. + */ + void initialize() { + mSearchables = createSearchables(); + mSearchDialog = new SearchDialogWrapper(mContext); + } + + private Searchables createSearchables() { + Searchables searchables = new Searchables(mContext); + searchables.buildSearchableList(); - // After startup settles down, preload the searchables list, - // which will reduce the delay when the search UI is invoked. - mHandler.post(mRunUpdateSearchable); + 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); - // allows disabling of search dialog for stress testing runs - mDisabledOnBoot = !TextUtils.isEmpty(SystemProperties.get(DISABLE_SEARCH_PROPERTY)); + return searchables; } /** - * Listens for intent broadcasts. - * - * The primary purpose here is to refresh the "searchables" list - * if packages are added/removed. + * Refreshes the "searchables" list when packages are added/removed. */ - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + 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. - */ - 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. + * Informs all listeners that the list of searchables has been updated. */ - 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 @@ public class SearchManagerService extends ISearchManager.Stub * @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. - */ - /*package*/ 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; - } - - mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData, - globalSearch); - if (searchManagerCallback != null) { - mCallback = 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. + * Can be called from any thread. */ public List<SearchableInfo> getSearchablesForWebSearch() { - updateSearchablesIfDirty(); + 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() { - updateSearchablesIfDirty(); + 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(ComponentName component) { + public void setDefaultWebSearch(final ComponentName component) { + if (mSearchables == null) return; mSearchables.setDefaultWebSearch(component); + broadcastSearchablesChanged(); } + // Search UI API + /** - * Runs an operation on the handler for the service, blocks until it returns, - * and returns the value returned by the operation. + * Launches the search UI. Can be called from any thread. * - * @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. + * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean) */ - 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; - } + public void startSearch(String initialQuery, + boolean selectInitialQuery, + ComponentName launchActivity, + Bundle appSearchData, + boolean globalSearch, + ISearchManagerCallback searchManagerCallback) { + if (mSearchDialog == null) return; + mSearchDialog.startSearch(initialQuery, + selectInitialQuery, + launchActivity, + appSearchData, + globalSearch, + searchManagerCallback); } - private static void debug(String msg) { - Thread thread = Thread.currentThread(); - Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")"); + /** + * Cancels the search dialog. Can be called from any thread. + */ + public void stopSearch() { + 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { } /** + * 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { 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.IntentFilter; 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 @@ public class Searchables { } // 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 @@ public class Searchables { 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 @@ public class Searchables { * @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 @@ public class Searchables { 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 @@ public class Searchables { // 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 @@ public class Searchables { 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 @@ public class Searchables { * 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/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 616b3f1..ed1e4ff 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -107,9 +107,7 @@ public class TextToSpeech { public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false - public static final String FALLBACK_TTS_DEFAULT_LANG = "eng"; - public static final String FALLBACK_TTS_DEFAULT_COUNTRY = ""; - public static final String FALLBACK_TTS_DEFAULT_VARIANT = ""; + public static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico"; // return codes for a TTS engine's check data activity public static final int CHECK_VOICE_DATA_PASS = 1; @@ -608,6 +606,7 @@ public class TextToSpeech { result = mITts.setLanguage(mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1], mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1], mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] ); + } catch (RemoteException e) { // TTS died; restart it. mStarted = false; initTts(); diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 4179edb..9071bf0 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -109,7 +109,6 @@ public class DisplayMetrics { */ public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation, int screenLayout) { - int xOffset = 0; if (!compatibilityInfo.isConfiguredExpandable()) { // Note: this assume that configuration is updated before calling // updateMetrics method. @@ -142,7 +141,6 @@ public class DisplayMetrics { if (defaultWidth < widthPixels) { // content/window's x offset in original pixels - xOffset = ((widthPixels - defaultWidth) / 2); widthPixels = defaultWidth; } if (defaultHeight < heightPixels) { @@ -154,7 +152,6 @@ public class DisplayMetrics { compatibilityInfo.setExpandable(true); } } - compatibilityInfo.setVisibleRect(xOffset, widthPixels, heightPixels); if (compatibilityInfo.isScalingRequired()) { float invertedRatio = compatibilityInfo.applicationInvertedScale; density *= invertedRatio; diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 45b0f0a..ff1eb53 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -306,7 +306,7 @@ public class SurfaceView extends View { // Use original size if the app specified the size of the view, // and let the flinger to scale up. - if (mRequestedWidth <= 0 && mTranslator != null && mTranslator.scalingRequired) { + if (mRequestedWidth <= 0 && mTranslator != null) { myWidth *= appScale; myHeight *= appScale; } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 6f6e224..6bcb135 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -385,6 +385,7 @@ public final class ViewRoot extends Handler implements ViewParent, if (mView == null) { mView = view; mWindowAttributes.copyFrom(attrs); + attrs = mWindowAttributes; CompatibilityInfo compatibilityInfo = mView.getContext().getResources().getCompatibilityInfo(); @@ -397,11 +398,14 @@ public final class ViewRoot extends Handler implements ViewParent, } if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs); + if (!compatibilityInfo.supportsScreen()) { + attrs.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; + } + mSoftInputMode = attrs.softInputMode; mWindowAttributesChanged = true; mAttachInfo.mRootView = view; - mAttachInfo.mScalingRequired = - mTranslator == null ? false : mTranslator.scalingRequired; + mAttachInfo.mScalingRequired = mTranslator == null ? false : true; mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale; if (panelParentView != null) { diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index bdb86d7..e96a15b 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -484,11 +484,19 @@ public interface WindowManager extends ViewManager { public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000; /** Window flag: special flag to let a window ignore the compatibility scaling. - * This is used by SurfaceView to create a window that does not scale the content. + * This is used by SurfaceView to pass this info into ViewRoot, and not used + * by WindowManager. * * {@hide} */ public static final int FLAG_NO_COMPATIBILITY_SCALING = 0x00100000; + /** Window flag: special flag to limit the size of the window to be + * original size ([320x480] x density). Used to create window for applications + * running under compatibility mode. + * + * {@hide} */ + public static final int FLAG_COMPATIBLE_WINDOW = 0x00200000; + /** Window flag: a special option intended for system dialogs. When * this flag is set, the window will demand focus unconditionally when * it is created. 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 class Toast { */ 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 class Toast { */ 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 class Toast { 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 @@ public class Toast { private static INotificationManager sService; - static private INotificationManager getService() - { + static private INotificationManager getService() { if (sService != null) { return sService; } @@ -295,28 +296,42 @@ public class Toast { 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 @@ public class Toast { /** * 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 class Toast { } } - 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 @@ public class Toast { 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/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 77a8a72..57b5aa6 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -55,6 +55,7 @@ public: ~JNICameraContext() { release(); } virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); + virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } void release(); @@ -188,6 +189,12 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) } } +void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) +{ + // TODO: plumb up to Java. For now, just drop the timestamp + postData(msgType, dataPtr); +} + // connect to camera service static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 6f2a5d3..fd78f83 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2888,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 32c6937..871c651 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1125,6 +1125,7 @@ <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" /> |
