diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-15 16:12:10 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-15 16:12:10 -0800 |
commit | 9266c558bf1d21ff647525ff99f7dadbca417309 (patch) | |
tree | 1630b1ba80f4793caf39d865528e662bdb1037fe /core/java/android/app | |
parent | b798689749c64baba81f02e10cf2157c747d6b46 (diff) | |
download | frameworks_base-9266c558bf1d21ff647525ff99f7dadbca417309.zip frameworks_base-9266c558bf1d21ff647525ff99f7dadbca417309.tar.gz frameworks_base-9266c558bf1d21ff647525ff99f7dadbca417309.tar.bz2 |
auto import from //branches/cupcake/...@126645
Diffstat (limited to 'core/java/android/app')
-rw-r--r-- | core/java/android/app/ActivityThread.java | 31 | ||||
-rw-r--r-- | core/java/android/app/AlertDialog.java | 10 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 12 | ||||
-rw-r--r-- | core/java/android/app/Dialog.java | 23 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 4 | ||||
-rw-r--r-- | core/java/android/app/SearchDialog.java | 129 |
6 files changed, 142 insertions, 67 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3d448a6..a98e295 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1072,6 +1072,7 @@ public final class ActivityThread { List<Intent> pendingIntents; boolean startsNotResumed; + boolean isForward; ActivityRecord() { parent = null; @@ -1225,8 +1226,8 @@ public final class ActivityThread { token); } - public final void scheduleResumeActivity(IBinder token) { - queueOrSendMessage(H.RESUME_ACTIVITY, token); + public final void scheduleResumeActivity(IBinder token, boolean isForward) { + queueOrSendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0); } public final void scheduleSendResult(IBinder token, List<ResultInfo> results) { @@ -1240,7 +1241,7 @@ public final class ActivityThread { // activity itself back to the activity manager. (matters more with ipc) public final void scheduleLaunchActivity(Intent intent, IBinder token, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed) { + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) { ActivityRecord r = new ActivityRecord(); r.token = token; @@ -1252,6 +1253,7 @@ public final class ActivityThread { r.pendingIntents = pendingNewIntents; r.startsNotResumed = notResumed; + r.isForward = isForward; queueOrSendMessage(H.LAUNCH_ACTIVITY, r); } @@ -1604,7 +1606,8 @@ public final class ActivityThread { handleWindowVisibility((IBinder)msg.obj, false); break; case RESUME_ACTIVITY: - handleResumeActivity((IBinder)msg.obj, true); + handleResumeActivity((IBinder)msg.obj, true, + msg.arg1 != 0); break; case SEND_RESULT: handleSendResult((ResultData)msg.obj); @@ -2167,7 +2170,7 @@ public final class ActivityThread { Activity a = performLaunchActivity(r); if (a != null) { - handleResumeActivity(r.token, false); + handleResumeActivity(r.token, false, r.isForward); if (!r.activity.mFinished && r.startsNotResumed) { // The activity manager actually wants this one to start out @@ -2522,7 +2525,7 @@ public final class ActivityThread { return r; } - final void handleResumeActivity(IBinder token, boolean clearHide) { + final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -2537,6 +2540,9 @@ public final class ActivityThread { a.mStartedActivity + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished); + final int forwardBit = isForward ? + WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; + // If the window hasn't yet been added to the window manager, // and this guy didn't finish itself or start another activity, // then go ahead and add the window. @@ -2548,6 +2554,7 @@ public final class ActivityThread { WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; + l.softInputMode |= forwardBit; wm.addView(decor, l); // If the window has already been added, but during resume @@ -2567,6 +2574,18 @@ public final class ActivityThread { performConfigurationChanged(r.activity, r.newConfig); r.newConfig = null; } + Log.v(TAG, "Resuming " + r + " with isForward=" + isForward); + WindowManager.LayoutParams l = r.window.getAttributes(); + if ((l.softInputMode + & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) + != forwardBit) { + l.softInputMode = (l.softInputMode + & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)) + | forwardBit; + ViewManager wm = a.getWindowManager(); + View decor = r.window.getDecorView(); + wm.updateViewLayout(decor, l); + } r.activity.mDecor.setVisibility(View.VISIBLE); mNumVisibleActivities++; } diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index a6981a5..f2b89c3 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.Message; import android.view.KeyEvent; import android.view.View; +import android.view.WindowManager; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListAdapter; @@ -41,6 +42,15 @@ import com.android.internal.app.AlertController; * FrameLayout fl = (FrameLayout) findViewById(R.id.body); * fl.add(myView, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); * </pre> + * + * <p>The AlertDialog class takes care of automatically setting + * {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM + * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether + * any views in the dialog return true from {@link View#onCheckIsTextEditor() + * View.onCheckIsTextEditor()}. Generally you want this set for a Dialog + * without text editors, so that it will be placed on top of the current + * input method UI. You can modify this behavior by forcing the flag to your + * desired mode after calling {@link #onCreate}. */ public class AlertDialog extends Dialog implements DialogInterface { private AlertController mAlert; diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 6a70329..54237ae 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -97,7 +97,8 @@ public abstract class ApplicationThreadNative extends Binder { data.enforceInterface(IApplicationThread.descriptor); IBinder b = data.readStrongBinder(); - scheduleResumeActivity(b); + boolean isForward = data.readInt() != 0; + scheduleResumeActivity(b, isForward); return true; } @@ -120,7 +121,8 @@ public abstract class ApplicationThreadNative extends Binder List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR); List<Intent> pi = data.createTypedArrayList(Intent.CREATOR); boolean notResumed = data.readInt() != 0; - scheduleLaunchActivity(intent, b, info, state, ri, pi, notResumed); + boolean isForward = data.readInt() != 0; + scheduleLaunchActivity(intent, b, info, state, ri, pi, notResumed, isForward); return true; } @@ -376,11 +378,12 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } - public final void scheduleResumeActivity(IBinder token) + public final void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(token); + data.writeInt(isForward ? 1 : 0); mRemote.transact(SCHEDULE_RESUME_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); @@ -399,7 +402,7 @@ class ApplicationThreadProxy implements IApplicationThread { public final void scheduleLaunchActivity(Intent intent, IBinder token, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed) + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); @@ -410,6 +413,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeTypedList(pendingResults); data.writeTypedList(pendingNewIntents); data.writeInt(notResumed ? 1 : 0); + data.writeInt(isForward ? 1 : 0); mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index f1d2e65..951b48d 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -48,13 +48,23 @@ import java.lang.ref.WeakReference; /** * Base class for Dialogs. * - * Note: Activities provide a facility to manage the creation, saving and + * <p>Note: Activities provide a facility to manage the creation, saving and * restoring of dialogs. See {@link Activity#onCreateDialog(int)}, * {@link Activity#onPrepareDialog(int, Dialog)}, * {@link Activity#showDialog(int)}, and {@link Activity#dismissDialog(int)}. If * these methods are used, {@link #getOwnerActivity()} will return the Activity * that managed this dialog. * + * <p>Often you will want to have a Dialog display on top of the current + * input method, because there is no reason for it to accept text. You can + * do this by setting the {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM + * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} window flag (assuming + * your Dialog takes input focus, as it the default) with the following code: + * + * <pre> + * getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + * </pre> */ public class Dialog implements DialogInterface, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener { @@ -209,7 +219,16 @@ public class Dialog implements DialogInterface, Window.Callback, onStart(); mDecor = mWindow.getDecorView(); - mWindowManager.addView(mDecor, mWindow.getAttributes()); + WindowManager.LayoutParams l = mWindow.getAttributes(); + if ((l.softInputMode + & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) { + WindowManager.LayoutParams nl = new WindowManager.LayoutParams(); + nl.copyFrom(l); + nl.softInputMode |= + WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; + l = nl; + } + mWindowManager.addView(mDecor, l); mShowing = true; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index ecd993a..a351581 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -45,11 +45,11 @@ public interface IApplicationThread extends IInterface { void scheduleStopActivity(IBinder token, boolean showWindow, int configChanges) throws RemoteException; void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException; - void scheduleResumeActivity(IBinder token) throws RemoteException; + void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException; void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException; void scheduleLaunchActivity(Intent intent, IBinder token, ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed) + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) throws RemoteException; void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, int configChanges, diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index f1c604c..495156e 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -38,6 +38,7 @@ import android.text.Editable; import android.text.InputType; import android.text.TextUtils; import android.text.TextWatcher; +import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; @@ -538,7 +539,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } updateWidgetState(); // Only do suggestions if actually typed by user - if (mSuggestionsAdapter.getNonUserQuery()) { + if (!mSuggestionsAdapter.getNonUserQuery()) { mPreviousSuggestionQuery = s.toString(); mUserQuery = mSearchTextField.getText().toString(); mUserQuerySelStart = mSearchTextField.getSelectionStart(); @@ -640,6 +641,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS if (DBG_LOG_TIMING == 1) { dbgLogTiming("doTextKey()"); } + // dispatch "typing in the list" first + if (mSearchTextField.isPopupShowing() && + mSearchTextField.getListSelection() != ListView.INVALID_POSITION) { + return onSuggestionsKey(v, keyCode, event); + } + // otherwise, dispatch an "edit view" key switch (keyCode) { case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_DPAD_CENTER: @@ -649,6 +656,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS return true; } break; + case KeyEvent.KEYCODE_DPAD_DOWN: + // capture the EditText state, so we can restore the user entry later + mUserQuery = mSearchTextField.getText().toString(); + mUserQuerySelStart = mSearchTextField.getSelectionStart(); + mUserQuerySelEnd = mSearchTextField.getSelectionEnd(); + // pass through - we're just watching here + break; default: if (event.getAction() == KeyEvent.ACTION_DOWN) { SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); @@ -668,24 +682,18 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * React to the user typing while the suggestions are focused. First, check for action * keys. If not handled, try refocusing regular characters into the EditText. In this case, * replace the query text (start typing fresh text). - * - * TODO: Move this code into mTextKeyListener, testing for a list entry being hilited */ - /* - View.OnKeyListener mSuggestionsKeyListener = new View.OnKeyListener() { - public boolean onKey(View v, int keyCode, KeyEvent event) { - boolean handled = false; - // also guard against possible race conditions (late arrival after dismiss) - if (mSearchable != null) { - handled = doSuggestionsKey(v, keyCode, event); - if (!handled) { - handled = refocusingKeyListener(v, keyCode, event); - } + private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) { + boolean handled = false; + // also guard against possible race conditions (late arrival after dismiss) + if (mSearchable != null) { + handled = doSuggestionsKey(v, keyCode, event); + if (!handled) { + handled = refocusingKeyListener(v, keyCode, event); } - return handled; } - }; - */ + return handled; + } /** * Per UI design, we're going to "steer" any typed keystrokes back into the EditText @@ -821,26 +829,26 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // First, check for enter or search (both of which we'll treat as a "click") if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { - AdapterView<?> av = (AdapterView<?>) v; - int position = av.getSelectedItemPosition(); - return launchSuggestion(av, position); + int position = mSearchTextField.getListSelection(); + return launchSuggestion(mSuggestionsAdapter, position); } - // Next, check for left/right moves while we'll manually grab and shift focus + // Next, check for left/right moves, which we use to "return" the user to the edit view if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { - // give focus to text editor - // but don't restore the user's original query - mLeaveJammedQueryOnRefocus = true; - if (mSearchTextField.requestFocus()) { - mLeaveJammedQueryOnRefocus = false; - if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { - mSearchTextField.setSelection(0); - } else { - mSearchTextField.setSelection(mSearchTextField.length()); - } - return true; - } - mLeaveJammedQueryOnRefocus = false; + // give "focus" to text editor, but don't restore the user's original query + int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? + 0 : mSearchTextField.length(); + mSearchTextField.setSelection(selPoint); + mSearchTextField.setListSelection(0); + mSearchTextField.clearListSelection(); + return true; + } + + // Next, check for an "up and out" move + if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mSearchTextField.getListSelection()) { + jamSuggestionQuery(false, null, -1); + // let ACTV complete the move + return false; } // Next, check for an "action key" @@ -849,11 +857,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS ((actionKey.mSuggestActionMsg != null) || (actionKey.mSuggestActionMsgColumn != null))) { // launch suggestion using action key column - ListView lv = (ListView) v; - int position = lv.getSelectedItemPosition(); + int position = mSearchTextField.getListSelection(); if (position >= 0) { - CursorAdapter ca = getSuggestionsAdapter(lv); - Cursor c = ca.getCursor(); + Cursor c = mSuggestionsAdapter.getCursor(); if (c.moveToPosition(position)) { final String actionMsg = getActionKeyMessage(c, actionKey); if (actionMsg != null && (actionMsg.length() > 0)) { @@ -977,19 +983,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS /** * Shared code for launching a query from a suggestion. - * - * @param av The AdapterView (really a ListView) containing the suggestions - * @param position The suggestion we'll be launching from - * - * @return Returns true if a successful launch, false if could not (e.g. bad position) - */ - private boolean launchSuggestion(AdapterView<?> av, int position) { - CursorAdapter ca = getSuggestionsAdapter(av); - return launchSuggestion(ca, position); - } - - /** - * Shared code for launching a query from a suggestion. * @param ca The cursor adapter containing the suggestions * @param position The suggestion we'll be launching from * @return true if a successful launch, false if could not (e.g. bad position) @@ -1116,6 +1109,36 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } /** + * Local subclass for AutoCompleteTextView + * + * This exists entirely to override the threshold method. Otherwise we just use the class + * as-is. + */ + public static class SearchAutoComplete extends AutoCompleteTextView { + + public SearchAutoComplete(Context context) { + super(null); + } + + public SearchAutoComplete(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * We always return true, so that the effective threshold is "zero". This allows us + * to provide "null" suggestions such as "just show me some recent entries". + */ + @Override + public boolean enoughToFilter() { + return true; + } + } + + /** * Support for AutoCompleteTextView-based suggestions */ /** @@ -1391,7 +1414,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * Implements OnItemClickListener */ public void onItemClick(AdapterView<?> parent, View view, int position, long id) { -// Log.d(LOG_TAG, "onItemClick() position " + position); + // Log.d(LOG_TAG, "onItemClick() position " + position); launchSuggestion(mSuggestionsAdapter, position); } @@ -1399,7 +1422,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * Implements OnItemSelectedListener */ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { -// Log.d(LOG_TAG, "onItemSelected() position " + position); + // Log.d(LOG_TAG, "onItemSelected() position " + position); jamSuggestionQuery(true, parent, position); } @@ -1407,7 +1430,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * Implements OnItemSelectedListener */ public void onNothingSelected(AdapterView<?> parent) { -// Log.d(LOG_TAG, "onNothingSelected()"); + // Log.d(LOG_TAG, "onNothingSelected()"); } /** |