diff options
35 files changed, 1297 insertions, 382 deletions
diff --git a/api/current.xml b/api/current.xml index 19c1384..357daae 100644 --- a/api/current.xml +++ b/api/current.xml @@ -21087,6 +21087,32 @@ <parameter name="nonRoot" type="boolean"> </parameter> </method> +<method name="onActionModeFinished" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mode" type="android.view.ActionMode"> +</parameter> +</method> +<method name="onActionModeStarted" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mode" type="android.view.ActionMode"> +</parameter> +</method> <method name="onActivityResult" return="void" abstract="false" @@ -21722,19 +21748,6 @@ visibility="protected" > </method> -<method name="onStartActionMode" - return="android.view.ActionMode" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="callback" type="android.view.ActionMode.Callback"> -</parameter> -</method> <method name="onStop" return="void" abstract="false" @@ -21835,6 +21848,19 @@ <parameter name="hasFocus" type="boolean"> </parameter> </method> +<method name="onWindowStartingActionMode" + return="android.view.ActionMode" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="callback" type="android.view.ActionMode.Callback"> +</parameter> +</method> <method name="openContextMenu" return="void" abstract="false" @@ -21885,47 +21911,6 @@ <parameter name="exitAnim" type="int"> </parameter> </method> -<method name="popBackStack" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="deprecated" - visibility="public" -> -</method> -<method name="popBackStack" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="deprecated" - visibility="public" -> -<parameter name="name" type="java.lang.String"> -</parameter> -<parameter name="flags" type="int"> -</parameter> -</method> -<method name="popBackStack" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="deprecated" - visibility="public" -> -<parameter name="id" type="int"> -</parameter> -<parameter name="flags" type="int"> -</parameter> -</method> <method name="registerForContextMenu" return="void" abstract="false" @@ -22611,17 +22596,6 @@ visibility="protected" > </field> -<field name="POP_BACK_STACK_INCLUSIVE" - type="int" - transient="false" - volatile="false" - value="1" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="RESULT_CANCELED" type="int" transient="false" @@ -25434,6 +25408,32 @@ visibility="public" > </method> +<method name="onActionModeFinished" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mode" type="android.view.ActionMode"> +</parameter> +</method> +<method name="onActionModeStarted" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mode" type="android.view.ActionMode"> +</parameter> +</method> <method name="onAttachedToWindow" return="void" abstract="false" @@ -25784,19 +25784,6 @@ visibility="protected" > </method> -<method name="onStartActionMode" - return="android.view.ActionMode" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="callback" type="android.view.ActionMode.Callback"> -</parameter> -</method> <method name="onStop" return="void" abstract="false" @@ -25860,6 +25847,19 @@ <parameter name="hasFocus" type="boolean"> </parameter> </method> +<method name="onWindowStartingActionMode" + return="android.view.ActionMode" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="callback" type="android.view.ActionMode.Callback"> +</parameter> +</method> <method name="openContextMenu" return="void" abstract="false" @@ -28308,6 +28308,17 @@ <parameter name="args" type="java.lang.String[]"> </parameter> </method> +<method name="executePendingTransactions" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="findFragmentById" return="android.app.Fragment" abstract="true" @@ -28374,7 +28385,7 @@ > </method> <method name="popBackStack" - return="boolean" + return="void" abstract="true" native="false" synchronized="false" @@ -28385,7 +28396,7 @@ > </method> <method name="popBackStack" - return="boolean" + return="void" abstract="true" native="false" synchronized="false" @@ -28400,6 +28411,47 @@ </parameter> </method> <method name="popBackStack" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="id" type="int"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<method name="popBackStackImmediate" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="popBackStackImmediate" + return="boolean" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="name" type="java.lang.String"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<method name="popBackStackImmediate" return="boolean" abstract="true" native="false" @@ -212083,6 +212135,32 @@ <parameter name="event" type="android.view.MotionEvent"> </parameter> </method> +<method name="onActionModeFinished" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mode" type="android.view.ActionMode"> +</parameter> +</method> +<method name="onActionModeStarted" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mode" type="android.view.ActionMode"> +</parameter> +</method> <method name="onAttachedToWindow" return="void" abstract="true" @@ -212217,8 +212295,8 @@ visibility="public" > </method> -<method name="onStartActionMode" - return="android.view.ActionMode" +<method name="onWindowAttributesChanged" + return="void" abstract="true" native="false" synchronized="false" @@ -212227,10 +212305,10 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.view.ActionMode.Callback"> +<parameter name="attrs" type="android.view.WindowManager.LayoutParams"> </parameter> </method> -<method name="onWindowAttributesChanged" +<method name="onWindowFocusChanged" return="void" abstract="true" native="false" @@ -212240,11 +212318,11 @@ deprecated="not deprecated" visibility="public" > -<parameter name="attrs" type="android.view.WindowManager.LayoutParams"> +<parameter name="hasFocus" type="boolean"> </parameter> </method> -<method name="onWindowFocusChanged" - return="void" +<method name="onWindowStartingActionMode" + return="android.view.ActionMode" abstract="true" native="false" synchronized="false" @@ -212253,7 +212331,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="hasFocus" type="boolean"> +<parameter name="callback" type="android.view.ActionMode.Callback"> </parameter> </method> </interface> diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 33f88d8..5174f19 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2086,63 +2086,12 @@ public class Activity extends ContextThemeWrapper } /** - * Flag for {@link #popBackStack(String, int)} - * and {@link #popBackStack(int, int)}: If set, and the name or ID of - * a back stack entry has been supplied, then all matching entries will - * be consumed until one that doesn't match is found or the bottom of - * the stack is reached. Otherwise, all entries up to but not including that entry - * will be removed. - */ - public static final int POP_BACK_STACK_INCLUSIVE = 1<<0; - - /** - * Pop the top state off the back stack. Returns true if there was one - * to pop, else false. - * @deprecated use {@link #getFragmentManager}. - */ - @Deprecated - public boolean popBackStack() { - return mFragments.popBackStack(); - } - - /** - * Pop the last fragment transition from the local activity's fragment - * back stack. If there is nothing to pop, false is returned. - * @param name If non-null, this is the name of a previous back state - * to look for; if found, all states up to that state will be popped. The - * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether - * the named state itself is popped. If null, only the top state is popped. - * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. - * @deprecated use {@link #getFragmentManager}. - */ - @Deprecated - public boolean popBackStack(String name, int flags) { - return mFragments.popBackStack(name, flags); - } - - /** - * Pop all back stack states up to the one with the given identifier. - * @param id Identifier of the stated to be popped. If no identifier exists, - * false is returned. - * The identifier is the number returned by - * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The - * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether - * the named state itself is popped. - * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. - * @deprecated use {@link #getFragmentManager}. - */ - @Deprecated - public boolean popBackStack(int id, int flags) { - return mFragments.popBackStack(id, flags); - } - - /** * Called when the activity has detected the user's press of the back * key. The default implementation simply finishes the current activity, * but you can override this to do whatever you want. */ public void onBackPressed() { - if (!mFragments.popBackStack()) { + if (!mFragments.popBackStackImmediate()) { finish(); } } @@ -4174,7 +4123,7 @@ public class Activity extends ContextThemeWrapper } /** - * Start a context mode. + * Start an action mode. * * @param callback Callback that will manage lifecycle events for this context mode * @return The ContextMode that was started, or null if it was canceled @@ -4185,7 +4134,18 @@ public class Activity extends ContextThemeWrapper return mWindow.getDecorView().startActionMode(callback); } - public ActionMode onStartActionMode(ActionMode.Callback callback) { + /** + * Give the Activity a chance to control the UI for an action mode requested + * by the system. + * + * <p>Note: If you are looking for a notification callback that an action mode + * has been started for this activity, see {@link #onActionModeStarted(ActionMode)}.</p> + * + * @param callback The callback that should control the new action mode + * @return The new action mode, or <code>null</code> if the activity does not want to + * provide special handling for this action mode. (It will be handled by the system.) + */ + public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { initActionBar(); if (mActionBar != null) { return mActionBar.startActionMode(callback); @@ -4193,6 +4153,24 @@ public class Activity extends ContextThemeWrapper return null; } + /** + * Notifies the Activity that an action mode has been started. + * Activity subclasses overriding this method should call the superclass implementation. + * + * @param mode The new action mode. + */ + public void onActionModeStarted(ActionMode mode) { + } + + /** + * Notifies the activity that an action mode has finished. + * Activity subclasses overriding this method should call the superclass implementation. + * + * @param mode The action mode that just finished. + */ + public void onActionModeFinished(ActionMode mode) { + } + // ------------------ Internal API ------------------ final void setParent(Activity parent) { diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 526129a..64a4d7a 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -867,13 +867,19 @@ public class Dialog implements DialogInterface, Window.Callback, } } - public ActionMode onStartActionMode(ActionMode.Callback callback) { + public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { if (mActionBar != null) { return mActionBar.startActionMode(callback); } return null; } + public void onActionModeStarted(ActionMode mode) { + } + + public void onActionModeFinished(ActionMode mode) { + } + /** * @return The activity associated with this dialog, or null if there is no associated activity. */ diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 0741d41..6e18533 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -1036,7 +1036,7 @@ public class DownloadManager { long destinationType = getLong(getColumnIndex(Downloads.Impl.COLUMN_DESTINATION)); if (destinationType == Downloads.Impl.DESTINATION_FILE_URI || destinationType == Downloads.Impl.DESTINATION_EXTERNAL) { - String localPath = getString(getColumnIndex(Downloads.Impl._DATA)); + String localPath = getString(getColumnIndex(COLUMN_LOCAL_FILENAME)); if (localPath == null) { return null; } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 9970418..d3a4f33 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter; import android.content.res.TypedArray; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -99,6 +100,20 @@ public abstract class FragmentManager { public abstract FragmentTransaction openTransaction(); /** + * After a {@link FragmentTransaction} is committed with + * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it + * is scheduled to be executed asynchronously on the process's main thread. + * If you want to immediately executing any such pending operations, you + * can call this function (only from the main thread) to do so. Note that + * all callbacks and other related behavior will be done from within this + * call, so be careful about where this is called from. + * + * @return Returns true if there were any pending transactions to be + * executed. + */ + public abstract boolean executePendingTransactions(); + + /** * Finds a fragment that was identified by the given id either when inflated * from XML or as the container ID when added in a transaction. This first * searches through fragments that are currently added to the manager's @@ -132,7 +147,15 @@ public abstract class FragmentManager { * Pop the top state off the back stack. Returns true if there was one * to pop, else false. */ - public abstract boolean popBackStack(); + public abstract void popBackStack(); + + /** + * Like {@link #popBackStack()}, but performs the operation immediately + * inside of the call. This is like calling {@link #executePendingTransactions()} + * afterwards. + * @return Returns true if there was something popped, else false. + */ + public abstract boolean popBackStackImmediate(); /** * Pop the last fragment transition from the manager's fragment @@ -143,7 +166,15 @@ public abstract class FragmentManager { * the named state itself is popped. If null, only the top state is popped. * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. */ - public abstract boolean popBackStack(String name, int flags); + public abstract void popBackStack(String name, int flags); + + /** + * Like {@link #popBackStack(String, int)}, but performs the operation immediately + * inside of the call. This is like calling {@link #executePendingTransactions()} + * afterwards. + * @return Returns true if there was something popped, else false. + */ + public abstract boolean popBackStackImmediate(String name, int flags); /** * Pop all back stack states up to the one with the given identifier. @@ -155,7 +186,15 @@ public abstract class FragmentManager { * the named state itself is popped. * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. */ - public abstract boolean popBackStack(int id, int flags); + public abstract void popBackStack(int id, int flags); + + /** + * Like {@link #popBackStack(int, int)}, but performs the operation immediately + * inside of the call. This is like calling {@link #executePendingTransactions()} + * afterwards. + * @return Returns true if there was something popped, else false. + */ + public abstract boolean popBackStackImmediate(int id, int flags); /** * Return the number of entries currently in the back stack. @@ -300,17 +339,58 @@ final class FragmentManagerImpl extends FragmentManager { } @Override - public boolean popBackStack() { + public boolean executePendingTransactions() { + return execPendingActions(); + } + + @Override + public void popBackStack() { + enqueueAction(new Runnable() { + @Override public void run() { + popBackStackState(mActivity.mHandler, null, -1, 0); + } + }, false); + } + + @Override + public boolean popBackStackImmediate() { + checkStateLoss(); + executePendingTransactions(); return popBackStackState(mActivity.mHandler, null, -1, 0); } @Override - public boolean popBackStack(String name, int flags) { + public void popBackStack(final String name, final int flags) { + enqueueAction(new Runnable() { + @Override public void run() { + popBackStackState(mActivity.mHandler, name, -1, flags); + } + }, false); + } + + @Override + public boolean popBackStackImmediate(String name, int flags) { + checkStateLoss(); + executePendingTransactions(); return popBackStackState(mActivity.mHandler, name, -1, flags); } @Override - public boolean popBackStack(int id, int flags) { + public void popBackStack(final int id, final int flags) { + if (id < 0) { + throw new IllegalArgumentException("Bad id: " + id); + } + enqueueAction(new Runnable() { + @Override public void run() { + popBackStackState(mActivity.mHandler, null, id, flags); + } + }, false); + } + + @Override + public boolean popBackStackImmediate(int id, int flags) { + checkStateLoss(); + executePendingTransactions(); if (id < 0) { throw new IllegalArgumentException("Bad id: " + id); } @@ -849,16 +929,20 @@ final class FragmentManagerImpl extends FragmentManager { return null; } + private void checkStateLoss() { + if (mStateSaved) { + throw new IllegalStateException( + "Can not perform this action after onSaveInstanceState"); + } + if (mNoTransactionsBecause != null) { + throw new IllegalStateException( + "Can not perform this action inside of " + mNoTransactionsBecause); + } + } + public void enqueueAction(Runnable action, boolean allowStateLoss) { if (!allowStateLoss) { - if (mStateSaved) { - throw new IllegalStateException( - "Can not perform this action after onSaveInstanceState"); - } - if (mNoTransactionsBecause != null) { - throw new IllegalStateException( - "Can not perform this action inside of " + mNoTransactionsBecause); - } + checkStateLoss(); } synchronized (this) { if (mActivity == null) { @@ -934,17 +1018,23 @@ final class FragmentManagerImpl extends FragmentManager { /** * Only call from main thread! */ - public void execPendingActions() { + public boolean execPendingActions() { if (mExecutingActions) { - throw new IllegalStateException("Recursive entry to execPendingActions"); + throw new IllegalStateException("Recursive entry to executePendingTransactions"); } + if (Looper.myLooper() != Looper.getMainLooper()) { + throw new IllegalStateException("Must be called from main thread of process"); + } + + boolean didSomething = false; + while (true) { int numActions; synchronized (this) { if (mPendingActions == null || mPendingActions.size() == 0) { - return; + return didSomething; } numActions = mPendingActions.size(); @@ -961,6 +1051,7 @@ final class FragmentManagerImpl extends FragmentManager { mTmpActions[i].run(); } mExecutingActions = false; + didSomething = true; } } @@ -984,19 +1075,14 @@ final class FragmentManagerImpl extends FragmentManager { if (mBackStack == null) { return false; } - if (name == null && id < 0 && (flags&Activity.POP_BACK_STACK_INCLUSIVE) == 0) { + if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) { int last = mBackStack.size()-1; if (last < 0) { return false; } final BackStackRecord bss = mBackStack.remove(last); - enqueueAction(new Runnable() { - public void run() { - if (DEBUG) Log.v(TAG, "Popping back stack state: " + bss); - bss.popFromBackStack(true); - reportBackStackChanged(); - } - }, false); + bss.popFromBackStack(true); + reportBackStackChanged(); } else { int index = -1; if (name != null || id >= 0) { @@ -1016,7 +1102,7 @@ final class FragmentManagerImpl extends FragmentManager { if (index < 0) { return false; } - if ((flags&Activity.POP_BACK_STACK_INCLUSIVE) != 0) { + if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) { index--; // Consume all following entries that match. while (index >= 0) { @@ -1038,16 +1124,12 @@ final class FragmentManagerImpl extends FragmentManager { for (int i=mBackStack.size()-1; i>index; i--) { states.add(mBackStack.remove(i)); } - enqueueAction(new Runnable() { - public void run() { - final int LAST = states.size()-1; - for (int i=0; i<=LAST; i++) { - if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); - states.get(i).popFromBackStack(i == LAST); - } - reportBackStackChanged(); - } - }, false); + final int LAST = states.size()-1; + for (int i=0; i<=LAST; i++) { + if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); + states.get(i).popFromBackStack(i == LAST); + } + reportBackStackChanged(); } return true; } @@ -1084,6 +1166,10 @@ final class FragmentManagerImpl extends FragmentManager { } Parcelable saveAllState() { + // Make sure all pending operations have now been executed to get + // our state update-to-date. + execPendingActions(); + mStateSaved = true; if (mActive == null || mActive.size() <= 0) { diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java index a47c66a..47a7696 100644 --- a/core/java/android/os/DropBoxManager.java +++ b/core/java/android/os/DropBoxManager.java @@ -169,7 +169,12 @@ public class DropBoxManager { is = getInputStream(); if (is == null) return null; byte[] buf = new byte[maxBytes]; - return new String(buf, 0, Math.max(0, is.read(buf))); + int readBytes = 0; + int n = 0; + while (n >= 0 && (readBytes += n) < maxBytes) { + n = is.read(buf, readBytes, maxBytes - readBytes); + } + return new String(buf, 0, readBytes); } catch (IOException e) { return null; } finally { diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 0ce69ad..39f3cee 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -23,6 +23,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.app.Fragment; import android.app.FragmentBreadCrumbs; +import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.ListActivity; import android.content.Context; @@ -902,7 +903,8 @@ public abstract class PreferenceActivity extends ListActivity implements } private void switchToHeaderInner(String fragmentName, Bundle args, int direction) { - getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE); + getFragmentManager().popBackStack(BACK_STACK_PREFS, + FragmentManager.POP_BACK_STACK_INCLUSIVE); Fragment f = Fragment.instantiate(this, fragmentName, args); FragmentTransaction transaction = getFragmentManager().openTransaction(); transaction.setTransition(direction == 0 ? FragmentTransaction.TRANSIT_NONE @@ -934,7 +936,8 @@ public abstract class PreferenceActivity extends ListActivity implements if (mCurHeader == header) { // This is the header we are currently displaying. Just make sure // to pop the stack up to its root state. - getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE); + getFragmentManager().popBackStack(BACK_STACK_PREFS, + FragmentManager.POP_BACK_STACK_INCLUSIVE); } else { int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader); switchToHeaderInner(header.fragment, header.fragmentArguments, direction); @@ -1061,14 +1064,14 @@ public abstract class PreferenceActivity extends ListActivity implements setResult(resultCode, resultData); finish(); } else { + // XXX be smarter about popping the stack. + onBackPressed(); if (caller != null) { if (caller.getTargetFragment() != null) { caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(), resultCode, resultData); } } - // XXX be smarter about popping the stack. - onBackPressed(); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index be49255..e6eb46e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6304,12 +6304,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; - if (p != null && ai != null && ai.mHardwareAccelerated) { - // fast-track for GL-enabled applications; just invalidate the whole hierarchy - // with a null dirty rect, which tells the ViewRoot to redraw everything - p.invalidateChild(this, null); - return; - } + if (p != null && ai != null) { final Rect r = ai.mTmpInvalRect; r.set(0, 0, mRight - mLeft, mBottom - mTop); diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index d5d9a2e..5385cd9 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -313,12 +313,31 @@ public abstract class Window { public boolean onSearchRequested(); /** - * Called when an action mode is being started. + * Called when an action mode is being started for this window. Gives the + * callback an opportunity to handle the action mode in its own unique and + * beautiful way. If this method returns null the system can choose a way + * to present the mode or choose not to start the mode at all. * * @param callback Callback to control the lifecycle of this action mode - * @return The ActionMode that was started, or null if it was canceled + * @return The ActionMode that was started, or null if the system should present it */ - public ActionMode onStartActionMode(ActionMode.Callback callback); + public ActionMode onWindowStartingActionMode(ActionMode.Callback callback); + + /** + * Called when an action mode has been started. The appropriate mode callback + * method will have already been invoked. + * + * @param mode The new mode that has just been started. + */ + public void onActionModeStarted(ActionMode mode); + + /** + * Called when an action mode has been finished. The appropriate mode callback + * method will have already been invoked. + * + * @param mode The mode that was just finished. + */ + public void onActionModeFinished(ActionMode mode); } public Window(Context context) { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 14dbfe2..06800d5 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2384,7 +2384,6 @@ public class WebView extends AbsoluteLayout Rect sendOurVisibleRect() { if (mZoomManager.isPreventingWebkitUpdates()) return mLastVisibleRectSent; - Rect rect = new Rect(); calcOurContentVisibleRect(rect); // Rect.equals() checks for null input. @@ -2937,7 +2936,8 @@ public class WebView extends AbsoluteLayout postInvalidate(); // So we draw again if (oldX != mScrollX || oldY != mScrollY) { onScrollChanged(mScrollX, mScrollY, oldX, oldY); - } else { + } else if (mScroller.getStartX() != mScrollX + || mScroller.getStartY() != mScrollY) { abortAnimation(); mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY); WebViewCore.resumePriority(); @@ -2970,6 +2970,7 @@ public class WebView extends AbsoluteLayout if ((dx | dy) == 0) { return false; } + abortAnimation(); if (animate) { // Log.d(LOGTAG, "startScroll: " + dx + " " + dy); mScroller.startScroll(mScrollX, mScrollY, dx, dy, @@ -2977,7 +2978,6 @@ public class WebView extends AbsoluteLayout awakenScrollBars(mScroller.getDuration()); invalidate(); } else { - abortAnimation(); // just in case scrollTo(x, y); } return true; diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index 1d103ed..1406e4e 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -110,8 +110,10 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On if (isShowing()) { mPopup.dismiss(); } - mTreeObserver.removeGlobalOnLayoutListener(this); - mTreeObserver = null; + if (mTreeObserver != null) { + mTreeObserver.removeGlobalOnLayoutListener(this); + mTreeObserver = null; + } } public boolean isShowing() { diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 0a4f543..e18f58f 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -40,6 +40,7 @@ import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; +import android.view.Window; import android.widget.AdapterView; import android.widget.HorizontalScrollView; import android.widget.ImageView; @@ -219,7 +220,7 @@ public class ActionBarView extends ViewGroup { Context context = getContext(); if (context instanceof Activity) { Activity activity = (Activity) context; - activity.onOptionsItemSelected(mLogoNavItem); + activity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem); } } }); diff --git a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml new file mode 100755 index 0000000..2b0e4af --- /dev/null +++ b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <accesspoint> + <ssid>opennet</ssid> + <security>NONE</security> + </accesspoint> + <accesspoint> + <ssid>GoogleGuest</ssid> + <security>NONE</security> + </accesspoint> + <accesspoint> + <ssid>securenetdhcp</ssid> + <security>PSK</security> + <password>androidwifi</password> + </accesspoint> + <accesspoint> + <ssid>botnet</ssid> + <security>EAP</security> + <eap>PEAP</eap> + <phase2>MSCHAPV2</phase2> + <identity>donut</identity> + <password>android</password> + </accesspoint> +</resources> + diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java new file mode 100644 index 0000000..863fbe6 --- /dev/null +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.connectivitymanagertest; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.AuthAlgorithm; +import android.net.wifi.WifiConfiguration.KeyMgmt; + +import android.util.Log; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + + +/** + * Help class to process configurations of access points saved in an XML file. + * The configurations of an access point is included in tag + * <accesspoint></accesspoint>. The supported configuration includes: ssid, + * security, eap, phase2, identity, password, anonymousidentity, cacert, usercert, + * in which each is included in the corresponding tags. All access points have to be + * enclosed in tags of <resources></resources>. + * + * The following is a sample configuration file for an access point using EAP-PEAP with MSCHAP2. + * <resources> + * <accesspoint> + * <ssid>testnet</ssid> + * <security>EAP</security> + * <eap>PEAP</eap> + * <phase2>MSCHAP2</phase2> + * <identity>donut</identity</identity> + * <password>abcdefgh</password> + * </accesspoint> + * </resources> + */ +public class AccessPointParserHelper { + private static final String KEYSTORE_SPACE = "keystore://"; + private static final String TAG = "AccessPointParserHelper"; + static final int NONE = 0; + static final int WEP = 1; + static final int PSK = 2; + static final int EAP = 3; + + List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); + + private int getSecurityType (String security) { + if (security.equalsIgnoreCase("NONE")) { + return NONE; + } else if (security.equalsIgnoreCase("WEP")) { + return WEP; + } else if (security.equalsIgnoreCase("PSK")) { + return PSK; + } else if (security.equalsIgnoreCase("EAP")) { + return EAP; + } else { + return -1; + } + } + + private boolean validateEapValue(String value) { + if (value.equalsIgnoreCase("PEAP") || + value.equalsIgnoreCase("TLS") || + value.equalsIgnoreCase("TTLS")) { + return true; + } else { + return false; + } + } + + DefaultHandler mHandler = new DefaultHandler() { + + boolean ssid = false; + boolean security = false; + boolean password = false; + boolean ip = false; + boolean subnetmask = false; + boolean gateway = false; + boolean dns = false; + boolean eap = false; + boolean phase2 = false; + boolean identity = false; + boolean anonymousidentity = false; + boolean cacert = false; + boolean usercert = false; + WifiConfiguration config = null; + int securityType = NONE; + + @Override + public void startElement(String uri, String localName, String tagName, + Attributes attributes) throws SAXException { + if (tagName.equalsIgnoreCase("accesspoint")) { + config = new WifiConfiguration(); + } + if (tagName.equalsIgnoreCase("ssid")) { + ssid = true; + } + if (tagName.equalsIgnoreCase("security")) { + security = true; + } + if (tagName.equalsIgnoreCase("password")) { + password = true; + } + if (tagName.equalsIgnoreCase("eap")) { + eap = true; + } + if (tagName.equalsIgnoreCase("phase2")) { + phase2 = true; + } + if (tagName.equalsIgnoreCase("identity")) { + identity = true; + } + if (tagName.equalsIgnoreCase("anonymousidentity")) { + anonymousidentity = true; + } + if (tagName.equalsIgnoreCase("cacert")) { + cacert = true; + } + if (tagName.equalsIgnoreCase("usercert")) { + usercert = true; + } + } + + @Override + public void endElement(String uri, String localName, String tagName) throws SAXException { + Log.v(TAG, "endElement: " + tagName); + if (tagName.equalsIgnoreCase("accesspoint")) { + networks.add(config); + } + } + + @Override + public void characters(char ch[], int start, int length) throws SAXException { + if (ssid) { + config.SSID = new String(ch, start, length); + Log.v(TAG, "ssid: " + config.SSID); + ssid = false; + } + if (security) { + String securityStr = (new String(ch, start, length)).toUpperCase(); + Log.v(TAG, "security: " + securityStr); + securityType = getSecurityType(securityStr); + Log.v(TAG, "securityType = " + securityType); + switch (securityType) { + case NONE: + config.allowedKeyManagement.set(KeyMgmt.NONE); + break; + case WEP: + config.allowedKeyManagement.set(KeyMgmt.NONE); + config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); + config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); + break; + case PSK: + config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + break; + case EAP: + config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); + config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + break; + default: + throw new SAXException(); + } + security = false; + } + if (password) { + String passwordStr = new String(ch, start, length); + int len = passwordStr.length(); + if (len == 0) { + throw new SAXException(); + } + Log.v(TAG, "passwordStr:" + passwordStr); + if (securityType == WEP) { + if ((len == 10 || len == 26 || len == 58) && + passwordStr.matches("[0-9A-Fa-f]*")) { + config.wepKeys[0] = passwordStr; + } else { + config.wepKeys[0] = '"' + passwordStr + '"'; + } + } else if (securityType == PSK) { + if (passwordStr.matches("[0-9A-Fa-f]{64}")) { + config.preSharedKey = passwordStr; + } else { + config.preSharedKey = '"' + passwordStr + '"'; + } + } else if (securityType == EAP) { + config.password.setValue(passwordStr); + } else { + throw new SAXException(); + } + password = false; + } + if (eap) { + String eapValue = new String(ch, start, length); + if (!validateEapValue(eapValue)) { + throw new SAXException(); + } + config.eap.setValue(eapValue); + eap = false; + } + if (phase2) { + String phase2Value = new String(ch, start, length); + config.phase2.setValue("auth=" + phase2Value); + phase2 = false; + } + if (identity) { + String identityValue = new String(ch, start, length); + config.identity.setValue(identityValue); + identity = false; + } + if (anonymousidentity) { + String anonyId = new String(ch, start, length); + config.anonymous_identity.setValue(anonyId); + anonymousidentity = false; + } + if (cacert) { + String cacertValue = new String(ch, start, length); + // need to install the credentail to "keystore://" + config.ca_cert.setValue(KEYSTORE_SPACE); + cacert = false; + } + if (usercert) { + String usercertValue = new String(ch, start, length); + config.client_cert.setValue(KEYSTORE_SPACE); + usercert = false; + } + } + }; + + public AccessPointParserHelper() { + } + + /** + * Process the accesspoint.xml file + * @return List of WifiConfiguration + * @throws Exception when parsing the XML file + */ + public List<WifiConfiguration> processAccessPoint(InputStream in) throws Exception { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser = factory.newSAXParser(); + saxParser.parse(in, mHandler); + return networks; + } +} diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java index e42b657..7c46e7a 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java @@ -16,8 +16,10 @@ package com.android.connectivitymanagertest; +import com.android.connectivitymanagertest.R; import android.app.Activity; import android.content.Context; +import android.content.res.Resources; import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; @@ -25,19 +27,22 @@ import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.view.KeyEvent; + +import java.io.InputStream; +import java.util.ArrayList; import java.util.List; import android.widget.LinearLayout; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.State; +import android.net.wifi.SupplicantState; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.net.wifi.WifiInfo; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration.KeyMgmt; - /** * An activity registered with connectivity manager broadcast * provides network connectivity information and @@ -46,8 +51,11 @@ import android.net.wifi.WifiConfiguration.KeyMgmt; public class ConnectivityManagerTestActivity extends Activity { public static final String LOG_TAG = "ConnectivityManagerTestActivity"; - public static final int WAIT_FOR_SCAN_RESULT = 5 * 1000; //5 seconds + public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds public static final int WIFI_SCAN_TIMEOUT = 20 * 1000; + public static final int SHORT_TIMEOUT = 5 * 1000; + public static final long LONG_TIMEOUT = 50 * 1000; + private static final String ACCESS_POINT_FILE = "accesspoints.xml"; public ConnectivityReceiver mConnectivityReceiver = null; public WifiReceiver mWifiReceiver = null; /* @@ -175,6 +183,7 @@ public class ConnectivityManagerTestActivity extends Activity { mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); registerReceiver(mWifiReceiver, mIntentFilter); // Get an instance of ConnectivityManager @@ -185,10 +194,26 @@ public class ConnectivityManagerTestActivity extends Activity { if (mWifiManager.isWifiEnabled()) { Log.v(LOG_TAG, "Clear Wifi before we start the test."); - clearWifi(); + removeConfiguredNetworksAndDisableWifi(); } } + public List<WifiConfiguration> loadNetworkConfigurations() throws Exception { + InputStream in = getAssets().open(ACCESS_POINT_FILE); + AccessPointParserHelper parseHelper = new AccessPointParserHelper(); + return parseHelper.processAccessPoint(in); + } + + private void printNetConfig(String[] configuration) { + for (int i = 0; i < configuration.length; i++) { + if (i == 0) { + Log.v(LOG_TAG, "SSID: " + configuration[0]); + } else { + Log.v(LOG_TAG, " " + configuration[i]); + } + } + } + // for each network type, initialize network states to UNKNOWN, and no verification flag is set public void initializeNetworkStates() { for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) { @@ -245,6 +270,68 @@ public class ConnectivityManagerTestActivity extends Activity { } } + // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, + // DISCONNECTING, DISCONNECTED, UNKNOWN + public boolean waitForNetworkState(int networkType, State expectedState, long timeout) { + long startTime = System.currentTimeMillis(); + while (true) { + if ((System.currentTimeMillis() - startTime) > timeout) { + if (mCM.getNetworkInfo(networkType).getState() != expectedState) { + return false; + } else { + // the broadcast has been sent out. the state has been changed. + Log.v(LOG_TAG, "networktype: " + networkType + " state: " + + mCM.getNetworkInfo(networkType)); + return true; + } + } + Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType + + " to be " + expectedState.toString()); + synchronized (connectivityObject) { + try { + connectivityObject.wait(SHORT_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if ((mNetworkInfo.getType() != networkType) || + (mNetworkInfo.getState() != expectedState)) { + Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() + + "is: " + mNetworkInfo.getState()); + continue; + } + return true; + } + } + } + + // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED, + // WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN + public boolean waitForWifiState(int expectedState, long timeout) { + long startTime = System.currentTimeMillis(); + while (true) { + if ((System.currentTimeMillis() - startTime) > timeout) { + if (mWifiState != expectedState) { + return false; + } else { + return true; + } + } + Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState); + synchronized (wifiObject) { + try { + wifiObject.wait(SHORT_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if (mWifiState != expectedState) { + Log.v(LOG_TAG, "Wifi state is: " + mWifiNetworkInfo.getState()); + continue; + } + return true; + } + } + } + // Return true if device is currently connected to mobile network public boolean isConnectedToMobile() { return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE); @@ -265,6 +352,22 @@ public class ConnectivityManagerTestActivity extends Activity { * We don't verify whether the connection is successful or not, leave this to the test */ public boolean connectToWifi(String knownSSID) { + WifiConfiguration config = new WifiConfiguration(); + config.SSID = knownSSID; + config.allowedKeyManagement.set(KeyMgmt.NONE); + return connectToWifiWithConfiguration(config); + } + + /** + * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration + * is pure string, we need to convert it to quoted string. + * @param config + * @return + */ + public boolean connectToWifiWithConfiguration(WifiConfiguration config) { + String ssid = config.SSID; + config.SSID = convertToQuotedString(ssid); + //If Wifi is not enabled, enable it if (!mWifiManager.isWifiEnabled()) { Log.v(LOG_TAG, "Wifi is not enabled, enable it"); @@ -273,6 +376,7 @@ public class ConnectivityManagerTestActivity extends Activity { List<ScanResult> netList = mWifiManager.getScanResults(); if (netList == null) { + Log.v(LOG_TAG, "scan results are null"); // if no scan results are available, start active scan mWifiManager.startScanActive(); mScanResultIsAvailable = false; @@ -299,17 +403,20 @@ public class ConnectivityManagerTestActivity extends Activity { } netList = mWifiManager.getScanResults(); + for (int i = 0; i < netList.size(); i++) { ScanResult sr= netList.get(i); - if (sr.SSID.equals(knownSSID)) { - Log.v(LOG_TAG, "found " + knownSSID + " in the scan result list"); - WifiConfiguration config = new WifiConfiguration(); - config.SSID = convertToQuotedString(sr.SSID); - config.allowedKeyManagement.set(KeyMgmt.NONE); + if (sr.SSID.equals(ssid)) { + Log.v(LOG_TAG, "found " + ssid + " in the scan result list"); int networkId = mWifiManager.addNetwork(config); // Connect to network by disabling others. mWifiManager.enableNetwork(networkId, true); mWifiManager.saveConfiguration(); + List<WifiConfiguration> wifiNetworks = mWifiManager.getConfiguredNetworks(); + for (WifiConfiguration netConfig : wifiNetworks) { + Log.v(LOG_TAG, netConfig.toString()); + } + mWifiManager.reconnect(); break; } @@ -317,14 +424,14 @@ public class ConnectivityManagerTestActivity extends Activity { List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks(); if (netConfList.size() <= 0) { - Log.v(LOG_TAG, knownSSID + " is not available"); + Log.v(LOG_TAG, ssid + " is not available"); return false; } return true; } /* - * Disconnect from the current AP + * Disconnect from the current AP and remove configured networks. */ public boolean disconnectAP() { if (mWifiManager.isWifiEnabled()) { @@ -360,9 +467,9 @@ public class ConnectivityManagerTestActivity extends Activity { } /** - * Disconnect from the current Wifi and clear the configuration list + * Remove configured networks and disable wifi */ - public boolean clearWifi() { + public boolean removeConfiguredNetworksAndDisableWifi() { if (!disconnectAP()) { return false; } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java index 592be92..3d4dc3d 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java @@ -21,6 +21,7 @@ import android.test.InstrumentationTestRunner; import android.test.InstrumentationTestSuite; import android.util.Log; import com.android.connectivitymanagertest.functional.ConnectivityManagerMobileTest; +import com.android.connectivitymanagertest.functional.WifiConnectionTest; import junit.framework.TestSuite; @@ -38,6 +39,7 @@ public class ConnectivityManagerTestRunner extends InstrumentationTestRunner { public TestSuite getAllTests() { TestSuite suite = new InstrumentationTestSuite(this); suite.addTestSuite(ConnectivityManagerMobileTest.class); + suite.addTestSuite(WifiConnectionTest.class); return suite; } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java index ad8d444..5959cf3 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java @@ -41,8 +41,6 @@ public class ConnectivityManagerMobileTest extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> { private static final String LOG_TAG = "ConnectivityManagerMobileTest"; private static final String PKG_NAME = "com.android.connectivitymanagertest"; - private static final long STATE_TRANSITION_SHORT_TIMEOUT = 5 * 1000; - private static final long STATE_TRANSITION_LONG_TIMEOUT = 30 * 1000; private String TEST_ACCESS_POINT; private ConnectivityManagerTestActivity cmActivity; @@ -64,9 +62,14 @@ public class ConnectivityManagerMobileTest wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "CMWakeLock"); wl.acquire(); // Each test case will start with cellular connection - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); - verifyCellularConnection(); + if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)) { + // Note: When the test fails in setUp(), tearDown is not called. In that case, + // the activity is destroyed which blocks the next test at "getActivity()". + // tearDown() is called hear to avoid that situation. + tearDown(); + fail("Device is not connected to Mobile, setUp failed"); + } } @Override @@ -74,86 +77,26 @@ public class ConnectivityManagerMobileTest cmActivity.finish(); Log.v(LOG_TAG, "tear down ConnectivityManagerTestActivity"); wl.release(); - cmActivity.clearWifi(); + cmActivity.removeConfiguredNetworksAndDisableWifi(); super.tearDown(); } // help function to verify 3G connection public void verifyCellularConnection() { - NetworkInfo extraNetInfo = cmActivity.mNetworkInfo; + NetworkInfo extraNetInfo = cmActivity.mCM.getActiveNetworkInfo(); assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE, - extraNetInfo.getType()); + extraNetInfo.getType()); assertTrue("not connected to cellular network", extraNetInfo.isConnected()); assertTrue("no data connection", cmActivity.mState.equals(State.CONNECTED)); } - // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, - // DISCONNECTING, DISCONNECTED, UNKNOWN - private void waitForNetworkState(int networkType, State expectedState, long timeout) { - long startTime = System.currentTimeMillis(); - while (true) { - if ((System.currentTimeMillis() - startTime) > timeout) { - if (cmActivity.mCM.getNetworkInfo(networkType).getState() != expectedState) { - assertFalse("Wait for network state timeout", true); - } else { - // the broadcast has been sent out. the state has been changed. - return; - } - } - Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType + - " to be " + expectedState.toString()); - synchronized (cmActivity.connectivityObject) { - try { - cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT); - } catch (InterruptedException e) { - e.printStackTrace(); - } - if ((cmActivity.mNetworkInfo.getType() != networkType) || - (cmActivity.mNetworkInfo.getState() != expectedState)) { - Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() + - "is: " + cmActivity.mNetworkInfo.getState()); - continue; - } - break; - } - } - } - - // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED, - // WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN - private void waitForWifiState(int expectedState, long timeout) { - long startTime = System.currentTimeMillis(); - while (true) { - if ((System.currentTimeMillis() - startTime) > timeout) { - if (cmActivity.mWifiState != expectedState) { - assertFalse("Wait for Wifi state timeout", true); - } else { - return; - } - } - Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState); - synchronized (cmActivity.wifiObject) { - try { - cmActivity.wifiObject.wait(5*1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - if (cmActivity.mWifiState != expectedState) { - Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState()); - continue; - } - break; - } - } - } - // Test case 1: Test enabling Wifi without associating with any AP @LargeTest public void test3GToWifiNotification() { // To avoid UNKNOWN state when device boots up cmActivity.enableWifi(); try { - Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -170,7 +113,7 @@ public class ConnectivityManagerMobileTest // Eanble Wifi cmActivity.enableWifi(); try { - Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -208,12 +151,13 @@ public class ConnectivityManagerMobileTest assertTrue("failed to connect to " + TEST_ACCESS_POINT, cmActivity.connectToWifi(TEST_ACCESS_POINT)); - waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); Log.v(LOG_TAG, "wifi state is enabled"); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); // validate states if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { @@ -237,12 +181,13 @@ public class ConnectivityManagerMobileTest // Connect to TEST_ACCESS_POINT assertTrue("failed to connect to " + TEST_ACCESS_POINT, cmActivity.connectToWifi(TEST_ACCESS_POINT)); - waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); try { - Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -255,11 +200,12 @@ public class ConnectivityManagerMobileTest } // Wait for the Wifi state to be DISABLED - waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); //Prepare for connectivity state verification NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); @@ -275,10 +221,10 @@ public class ConnectivityManagerMobileTest cmActivity.enableWifi(); // Wait for Wifi to be connected and mobile to be disconnected - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); // validate wifi states if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { @@ -298,12 +244,12 @@ public class ConnectivityManagerMobileTest assertTrue("failed to connect to " + TEST_ACCESS_POINT, cmActivity.connectToWifi(TEST_ACCESS_POINT)); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); // Wait for a few seconds to avoid the state that both Mobile and Wifi is connected try { - Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -318,12 +264,12 @@ public class ConnectivityManagerMobileTest NetworkState.TO_DISCONNECTION, State.DISCONNECTED); // clear Wifi - cmActivity.clearWifi(); + cmActivity.removeConfiguredNetworksAndDisableWifi(); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); // validate states if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { @@ -357,7 +303,7 @@ public class ConnectivityManagerMobileTest // Enable airplane mode cmActivity.setAirplaneMode(getInstrumentation().getContext(), true); try { - Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -389,8 +335,8 @@ public class ConnectivityManagerMobileTest // disable airplane mode cmActivity.setAirplaneMode(getInstrumentation().getContext(), false); - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); // Validate the state transition if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) { @@ -414,8 +360,8 @@ public class ConnectivityManagerMobileTest // Eanble airplane mode cmActivity.setAirplaneMode(getInstrumentation().getContext(), true); - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE, @@ -429,8 +375,8 @@ public class ConnectivityManagerMobileTest // Connect to Wifi assertTrue("failed to connect to " + TEST_ACCESS_POINT, cmActivity.connectToWifi(TEST_ACCESS_POINT)); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); // validate state and broadcast if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { @@ -457,11 +403,11 @@ public class ConnectivityManagerMobileTest assertTrue("failed to connect to " + TEST_ACCESS_POINT, cmActivity.connectToWifi(TEST_ACCESS_POINT)); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); try { - Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -469,11 +415,11 @@ public class ConnectivityManagerMobileTest // Enable airplane mode without clearing Wifi cmActivity.setAirplaneMode(getInstrumentation().getContext(), true); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); try { - Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -487,10 +433,10 @@ public class ConnectivityManagerMobileTest // Disable airplane mode cmActivity.setAirplaneMode(getInstrumentation().getContext(), false); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); // validate the state transition if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { @@ -508,14 +454,15 @@ public class ConnectivityManagerMobileTest //Connect to TEST_ACCESS_POINT assertTrue("failed to connect to " + TEST_ACCESS_POINT, cmActivity.connectToWifi(TEST_ACCESS_POINT)); - waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT); - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); assertNotNull("Not associated with any AP", cmActivity.mWifiManager.getConnectionInfo().getBSSID()); try { - Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT); + Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { Log.v(LOG_TAG, "exception: " + e.toString()); } @@ -527,13 +474,14 @@ public class ConnectivityManagerMobileTest } // Verify the connectivity state for Wifi is DISCONNECTED - waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, - STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); if (!cmActivity.disableWifi()) { Log.v(LOG_TAG, "disable Wifi failed"); return; } - waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT); + assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED, + ConnectivityManagerTestActivity.LONG_TIMEOUT)); } } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java new file mode 100644 index 0000000..69eb5db --- /dev/null +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.connectivitymanagertest.functional; + +import com.android.connectivitymanagertest.ConnectivityManagerTestActivity; +import com.android.connectivitymanagertest.NetworkState; + +import android.R; +import android.app.Activity; +import android.content.Intent; +import android.content.Context; +import android.content.res.Resources; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.NetworkInfo.State; + +import android.test.suitebuilder.annotation.LargeTest; +import android.test.ActivityInstrumentationTestCase2; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test Wi-Fi connection with different configuration + * To run this tests: + * adb shell am instrument -e class + * com.android.connectivitymanagertest.functional.WifiConnectionTest + * -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner + */ +public class WifiConnectionTest + extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> { + private static final String TAG = "WifiConnectionTest"; + private static final boolean DEBUG = true; + private static final String PKG_NAME = "com.android.connectivitymanagertests"; + private List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); + private ConnectivityManagerTestActivity mAct; + + public WifiConnectionTest() { + super(PKG_NAME, ConnectivityManagerTestActivity.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + mAct = getActivity(); + networks = mAct.loadNetworkConfigurations(); + if (DEBUG) { + printNetworkConfigurations(); + } + + // enable Wifi and verify wpa_supplicant is started + assertTrue("enable Wifi failed", mAct.enableWifi()); + try { + Thread.sleep( 2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT); + } catch (Exception e) { + fail("interrupted while waiting for WPA_SUPPLICANT to start"); + } + WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo(); + assertNotNull(mConnection); + assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant()); + } + + private void printNetworkConfigurations() { + Log.v(TAG, "==== print network configurations parsed from XML file ===="); + Log.v(TAG, "number of access points: " + networks.size()); + for (WifiConfiguration config : networks) { + Log.v(TAG, config.toString()); + } + } + + @Override + public void tearDown() throws Exception { + mAct.removeConfiguredNetworksAndDisableWifi(); + super.tearDown(); + } + + /** + * Connect to the provided Wi-Fi network + * @param config is the network configuration + * @return true if the connection is successful. + */ + private void connectToWifi(WifiConfiguration config) { + // step 1: connect to the test access point + assertTrue("failed to connect to " + config.SSID, + mAct.connectToWifiWithConfiguration(config)); + + // step 2: verify Wifi state and network state; + assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED, + ConnectivityManagerTestActivity.SHORT_TIMEOUT)); + assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, + State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT)); + + // step 3: verify the current connected network is the given SSID + if (DEBUG) { + Log.v(TAG, "config.SSID = " + config.SSID); + Log.v(TAG, "mAct.mWifiManager.getConnectionInfo.getSSID()" + + mAct.mWifiManager.getConnectionInfo().getSSID()); + } + assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID())); + + // Maintain the connection for 50 seconds before switching + try { + Thread.sleep(50*1000); + } catch (Exception e) { + fail("interrupted while waiting for WPA_SUPPLICANT to start"); + } + } + + @LargeTest + public void testWifiConnections() { + for (int i = 0; i < networks.size(); i++) { + connectToWifi(networks.get(i)); + mAct.removeConfiguredNetworksAndDisableWifi(); + } + } +} diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java index f019599..43cf06a 100644 --- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java +++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java @@ -110,6 +110,21 @@ public class BluetoothStressTest extends InstrumentationTestCase { mTestUtils.disable(adapter); } + public void testAcceptPair() { + int iterations = BluetoothTestRunner.sPairIterations; + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPairAddress); + mTestUtils.enable(adapter); + + for (int i = 0; i < iterations; i++) { + mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations); + mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey, + BluetoothTestRunner.sPairPin); + mTestUtils.unpair(adapter, device); + } + mTestUtils.disable(adapter); + } + public void testConnectA2dp() { int iterations = BluetoothTestRunner.sConnectA2dpIterations; if (iterations == 0) { diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java index 328891c..29dee34 100644 --- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java +++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java @@ -137,7 +137,6 @@ public class BluetoothTestUtils extends Assert { @Override public void onReceive(Context context, Intent intent) { - Log.i("BT", intent.toString()); if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) { setFiredFlag(DISCOVERY_STARTED_FLAG); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) { @@ -203,7 +202,7 @@ public class BluetoothTestUtils extends Assert { if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) { int varient = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1); assertNotSame(-1, varient); - switch(varient) { + switch (varient) { case BluetoothDevice.PAIRING_VARIANT_PIN: mDevice.setPin(mPin); break; @@ -252,7 +251,7 @@ public class BluetoothTestUtils extends Assert { mDevice = device; mProfile = profile; - switch(mProfile) { + switch (mProfile) { case BluetoothProfile.A2DP: mConnectionAction = BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED; break; @@ -384,11 +383,14 @@ public class BluetoothTestUtils extends Assert { mask = 0; // Don't check for received intents since we might have missed them. break; case BluetoothAdapter.STATE_OFF: - case BluetoothAdapter.STATE_TURNING_OFF: assertFalse(adapter.isEnabled()); start = System.currentTimeMillis(); assertTrue(adapter.enable()); break; + case BluetoothAdapter.STATE_TURNING_OFF: + start = System.currentTimeMillis(); + assertTrue(adapter.enable()); + break; default: removeReceiver(receiver); fail(String.format("enable() invalid state: state=%d", state)); @@ -410,7 +412,6 @@ public class BluetoothTestUtils extends Assert { return; } } else { - assertFalse(adapter.isEnabled()); assertEquals(BluetoothAdapter.STATE_TURNING_ON, state); } sleep(POLL_TIME); @@ -437,7 +438,6 @@ public class BluetoothTestUtils extends Assert { case BluetoothAdapter.STATE_TURNING_ON: assertFalse(adapter.isEnabled()); start = System.currentTimeMillis(); - assertTrue(adapter.disable()); break; case BluetoothAdapter.STATE_ON: assertTrue(adapter.isEnabled()); @@ -470,7 +470,6 @@ public class BluetoothTestUtils extends Assert { return; } } else { - assertFalse(adapter.isEnabled()); assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state); } sleep(POLL_TIME); @@ -629,11 +628,22 @@ public class BluetoothTestUtils extends Assert { } public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) { + pairOrAcceptPair(adapter, device, passkey, pin, true); + } + + public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, + byte[] pin) { + pairOrAcceptPair(adapter, device, passkey, pin, false); + } + + private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, + byte[] pin, boolean pair) { int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG; long start = -1; + String methodName = pair ? "pair()" : "acceptPair()"; if (!adapter.isEnabled()) { - fail("pair() bluetooth not enabled"); + fail(methodName + " bluetooth not enabled"); } PairReceiver receiver = getPairReceiver(device, passkey, pin, mask); @@ -643,7 +653,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothDevice.BOND_NONE: assertFalse(adapter.getBondedDevices().contains(device)); start = System.currentTimeMillis(); - assertTrue(device.createBond()); + if (pair) { + assertTrue(device.createBond()); + } break; case BluetoothDevice.BOND_BONDING: mask = 0; // Don't check for received intents since we might have missed them. @@ -653,7 +665,8 @@ public class BluetoothTestUtils extends Assert { return; default: removeReceiver(receiver); - fail(String.format("pair() invalid state: device=%s, state=%d", device, state)); + fail(String.format("%s invalid state: device=%s, state=%d", methodName, device, + state)); } long s = System.currentTimeMillis(); @@ -664,10 +677,10 @@ public class BluetoothTestUtils extends Assert { if ((receiver.getFiredFlags() & mask) == mask) { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { - writeOutput(String.format("pair() completed in %d ms: device=%s", + writeOutput(String.format("%s completed in %d ms: device=%s", methodName, (finish - start), device)); } else { - writeOutput(String.format("pair() completed: device=%s", device)); + writeOutput(String.format("%s completed: device=%s", methodName, device)); } removeReceiver(receiver); return; @@ -678,9 +691,9 @@ public class BluetoothTestUtils extends Assert { int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); - fail(String.format("pair() timeout: device=%s, state=%d (expected %d), " - + "flags=0x%x (expected 0x%x)", device, state, BluetoothDevice.BOND_BONDED, - firedFlags, mask)); + fail(String.format("%s timeout: device=%s, state=%d (expected %d), " + + "flags=0x%x (expected 0x%x)", methodName, device, state, + BluetoothDevice.BOND_BONDED, firedFlags, mask)); } public void unpair(BluetoothAdapter adapter, BluetoothDevice device) { @@ -788,7 +801,7 @@ public class BluetoothTestUtils extends Assert { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { writeOutput(String.format("connectProfile() completed in %d ms: " - +"device=%s, profile=%d", (finish - start), device, profile)); + + "device=%s, profile=%d", (finish - start), device, profile)); } else { writeOutput(String.format("connectProfile() completed: device=%s, " + "profile=%d", device, profile)); @@ -857,7 +870,7 @@ public class BluetoothTestUtils extends Assert { long finish = receiver.getCompletedTime(); if (start != -1 && finish != -1) { writeOutput(String.format("disconnectProfile() completed in %d ms: " - +"device=%s, profile=%d", (finish - start), device, profile)); + + "device=%s, profile=%d", (finish - start), device, profile)); } else { writeOutput(String.format("disconnectProfile() completed: device=%s, " + "profile=%d", device, profile)); @@ -934,14 +947,12 @@ public class BluetoothTestUtils extends Assert { long s = System.currentTimeMillis(); switch (profile) { case BluetoothProfile.A2DP: - while (mA2dp != null - && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { + while (mA2dp != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { sleep(POLL_TIME); } return mA2dp; case BluetoothProfile.HEADSET: - while (mHeadset != null - && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { + while (mHeadset != null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { sleep(POLL_TIME); } return mHeadset; diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs index 698540b..3e81115 100644 --- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs @@ -64,7 +64,7 @@ static void computeGaussianWeights() { static void copyInput() { - rs_allocation ain = {0}; + rs_allocation ain; rsSetObject(&ain,rsGetAllocation(InPixel)); uint32_t dimx = rsAllocationGetDimX(ain); uint32_t dimy = rsAllocationGetDimY(ain); @@ -73,7 +73,6 @@ static void copyInput() { ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]); } } - rsClearObject(&ain); } void filter() { diff --git a/libs/rs/java/Samples/src/com/android/samples/rslist.rs b/libs/rs/java/Samples/src/com/android/samples/rslist.rs index f29276a..0baccb8 100644 --- a/libs/rs/java/Samples/src/com/android/samples/rslist.rs +++ b/libs/rs/java/Samples/src/com/android/samples/rslist.rs @@ -46,7 +46,7 @@ int root(int launchID) { rsgBindFont(gItalic); color(0.2, 0.2, 0.2, 0); - rs_allocation listAlloc = {0}; + rs_allocation listAlloc; rsSetObject(&listAlloc, rsGetAllocation(gList)); int allocSize = rsAllocationGetDimX(listAlloc); @@ -67,7 +67,6 @@ int root(int launchID) { } currentYPos += itemHeight; } - rsClearObject(&listAlloc); return 10; } diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs index d1fde57..f354a72 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs @@ -47,7 +47,7 @@ int root(int launchID) { rsgBindFont(gFont); color(0.2, 0.2, 0.2, 0); - rs_allocation listAlloc = {0}; + rs_allocation listAlloc; rsSetObject(&listAlloc, rsGetAllocation(gList)); int allocSize = rsAllocationGetDimX(listAlloc); @@ -103,7 +103,6 @@ int root(int launchID) { } currentYPos += itemHeight; } - rsClearObject(&listAlloc); return 10; } diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp index df9f107..9524884 100644 --- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp +++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp @@ -36,6 +36,7 @@ AACEncoder::AACEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta) mStarted(false), mBufferGroup(NULL), mInputBuffer(NULL), + mInputFrame(NULL), mEncoderHandle(NULL), mApiHandle(NULL), mMemOperator(NULL) { @@ -45,6 +46,7 @@ status_t AACEncoder::initCheck() { CHECK(mApiHandle == NULL && mEncoderHandle == NULL); CHECK(mMeta->findInt32(kKeySampleRate, &mSampleRate)); CHECK(mMeta->findInt32(kKeyChannelCount, &mChannels)); + CHECK(mChannels <= 2 && mChannels >= 1); CHECK(mMeta->findInt32(kKeyBitRate, &mBitRate)); mApiHandle = new VO_AUDIO_CODECAPI; @@ -145,6 +147,10 @@ status_t AACEncoder::start(MetaData *params) { mNumInputSamples = 0; mAnchorTimeUs = 0; mFrameCount = 0; + + mInputFrame = new int16_t[mChannels * kNumSamplesPerFrame]; + CHECK(mInputFrame != NULL); + mSource->start(params); mStarted = true; @@ -176,6 +182,10 @@ status_t AACEncoder::stop() { mApiHandle = NULL; mStarted = false; + if (mInputFrame) { + delete[] mInputFrame; + mInputFrame = NULL; + } return OK; } @@ -222,7 +232,8 @@ status_t AACEncoder::read( buffer->meta_data()->setInt32(kKeyIsCodecConfig, false); } - while (mNumInputSamples < kNumSamplesPerFrame) { + const int32_t nSamples = mChannels * kNumSamplesPerFrame; + while (mNumInputSamples < nSamples) { if (mInputBuffer == NULL) { if (mSource->read(&mInputBuffer, options) != OK) { if (mNumInputSamples == 0) { @@ -231,7 +242,7 @@ status_t AACEncoder::read( } memset(&mInputFrame[mNumInputSamples], 0, - sizeof(int16_t) * (kNumSamplesPerFrame - mNumInputSamples)); + sizeof(int16_t) * (nSamples - mNumInputSamples)); mNumInputSamples = 0; break; } @@ -250,8 +261,7 @@ status_t AACEncoder::read( } else { readFromSource = false; } - size_t copy = - (kNumSamplesPerFrame - mNumInputSamples) * sizeof(int16_t); + size_t copy = (nSamples - mNumInputSamples) * sizeof(int16_t); if (copy > mInputBuffer->range_length()) { copy = mInputBuffer->range_length(); @@ -271,8 +281,8 @@ status_t AACEncoder::read( mInputBuffer = NULL; } mNumInputSamples += copy / sizeof(int16_t); - if (mNumInputSamples >= kNumSamplesPerFrame) { - mNumInputSamples %= kNumSamplesPerFrame; + if (mNumInputSamples >= nSamples) { + mNumInputSamples %= nSamples; break; } } @@ -280,7 +290,7 @@ status_t AACEncoder::read( VO_CODECBUFFER inputData; memset(&inputData, 0, sizeof(inputData)); inputData.Buffer = (unsigned char*) mInputFrame; - inputData.Length = kNumSamplesPerFrame * sizeof(int16_t); + inputData.Length = nSamples * sizeof(int16_t); CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData)); VO_CODECBUFFER outputData; @@ -289,15 +299,21 @@ status_t AACEncoder::read( memset(&outputInfo, 0, sizeof(outputInfo)); VO_U32 ret = VO_ERR_NONE; - outputData.Buffer = outPtr; - outputData.Length = buffer->size(); - ret = mApiHandle->GetOutputData(mEncoderHandle, &outputData, &outputInfo); - CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL); - CHECK(outputData.Length != 0); - buffer->set_range(0, outputData.Length); + size_t nOutputBytes = 0; + do { + outputData.Buffer = outPtr; + outputData.Length = buffer->size() - nOutputBytes; + ret = mApiHandle->GetOutputData(mEncoderHandle, &outputData, &outputInfo); + if (ret == VO_ERR_NONE) { + outPtr += outputData.Length; + nOutputBytes += outputData.Length; + } + } while (ret != VO_ERR_INPUT_BUFFER_SMALL); + buffer->set_range(0, nOutputBytes); int64_t mediaTimeUs = ((mFrameCount - 1) * 1000000LL * kNumSamplesPerFrame) / mSampleRate; + buffer->meta_data()->setInt64(kKeyTime, mAnchorTimeUs + mediaTimeUs); if (readFromSource && wallClockTimeUs != -1) { buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs); diff --git a/media/libstagefright/httplive/LiveSource.cpp b/media/libstagefright/httplive/LiveSource.cpp index 39e3e75..f9d27eb 100644 --- a/media/libstagefright/httplive/LiveSource.cpp +++ b/media/libstagefright/httplive/LiveSource.cpp @@ -278,7 +278,19 @@ bool LiveSource::switchToNext() { } if (mLastFetchTimeUs < 0) { - mPlaylistIndex = 0; + if (isSeekable()) { + mPlaylistIndex = 0; + } else { + // This is live streamed content, the first seqnum in the + // various bandwidth' streams may be slightly off, so don't + // start at the very first entry. + // With a segment duration of 6-10secs, this really only + // delays playback up to 30secs compared to real time. + mPlaylistIndex = 3; + if (mPlaylistIndex >= mPlaylist->size()) { + mPlaylistIndex = mPlaylist->size() - 1; + } + } } else { if (nextSequenceNumber < mFirstItemSequenceNumber || nextSequenceNumber diff --git a/media/libstagefright/include/AACEncoder.h b/media/libstagefright/include/AACEncoder.h index ecc533f..3d5fc60 100644 --- a/media/libstagefright/include/AACEncoder.h +++ b/media/libstagefright/include/AACEncoder.h @@ -60,7 +60,7 @@ class AACEncoder: public MediaSource { kNumSamplesPerFrame = 1024, }; - int16_t mInputFrame[kNumSamplesPerFrame]; + int16_t *mInputFrame; uint8_t mAudioSpecificConfigData[2]; // auido specific data void *mEncoderHandle; diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png Binary files differnew file mode 100644 index 0000000..4434b5c --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_quicksettings.png diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml index a7c91f5..02f9a90 100644 --- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml +++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notification_peek.xml @@ -19,7 +19,7 @@ --> <!-- android:background="@drawable/status_bar_closed_default_background" --> -<com.android.systemui.statusbar.tablet.NotificationPanel +<com.android.systemui.statusbar.tablet.NotificationPeekPanel xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:layout_width="match_parent" @@ -40,4 +40,4 @@ android:descendantFocusability="afterDescendants" > </FrameLayout> -</com.android.systemui.statusbar.tablet.NotificationPanel> +</com.android.systemui.statusbar.tablet.NotificationPeekPanel> diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml index 6a8ae40..884a473 100644 --- a/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml +++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_notifications.xml @@ -44,13 +44,27 @@ android:gravity="right" /> - <Button + <ImageView android:id="@+id/settings_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/date" android:layout_alignParentRight="true" - android:text="@string/system_panel_settings_button" + android:paddingRight="10dp" + android:src="@drawable/ic_sysbar_quicksettings" + android:baseline="17dp" + /> + + <ImageView + android:id="@+id/notification_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBaseline="@id/settings_button" + android:layout_alignParentRight="true" + android:paddingRight="10dp" + android:visibility="invisible" + android:src="@drawable/status_bar_veto" + android:baseline="17dp" /> <ImageView @@ -93,6 +107,13 @@ android:text="@string/system_panel_settings_button" /> + <FrameLayout + android:id="@+id/settings_frame" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_below="@id/settings_button" + /> + <ScrollView android:id="@+id/notificationScroller" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_settings.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_settings.xml new file mode 100644 index 0000000..c6ddfed --- /dev/null +++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_settings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +--> + +<com.android.systemui.statusbar.tablet.SettingsPanel + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="200dip" + > +</com.android.systemui.statusbar.tablet.SettingsPanel> + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java index 1a08f22..ce81fdc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java @@ -18,13 +18,25 @@ package com.android.systemui.statusbar.tablet; import android.content.Context; import android.util.AttributeSet; +import android.util.Slog; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; +import android.view.View; +import android.widget.FrameLayout; import com.android.systemui.R; -public class NotificationPanel extends RelativeLayout implements StatusBarPanel { +public class NotificationPanel extends RelativeLayout implements StatusBarPanel, + View.OnClickListener { + static final String TAG = "NotificationPanel"; + + View mSettingsButton; + View mNotificationButton; + View mNotificationScroller; + FrameLayout mSettingsFrame; + View mSettingsPanel; + public NotificationPanel(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -33,6 +45,51 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel super(context, attrs, defStyle); } + @Override + public void onFinishInflate() { + super.onFinishInflate(); + + mSettingsButton = (ImageView)findViewById(R.id.settings_button); + mSettingsButton.setOnClickListener(this); + mNotificationButton = (ImageView)findViewById(R.id.notification_button); + mNotificationButton.setOnClickListener(this); + + mNotificationScroller = findViewById(R.id.notificationScroller); + mSettingsFrame = (FrameLayout)findViewById(R.id.settings_frame); + } + + @Override + public void onVisibilityChanged(View v, int vis) { + super.onVisibilityChanged(v, vis); + // when we hide, put back the notifications + if (!isShown()) { + switchToNotificationMode(); + } + } + + public void onClick(View v) { + if (v == mSettingsButton) { + switchToSettingsMode(); + } else if (v == mNotificationButton) { + switchToNotificationMode(); + } + } + + public void switchToSettingsMode() { + removeSettingsPanel(); + addSettingsPanel(); + mSettingsButton.setVisibility(View.INVISIBLE); + mNotificationScroller.setVisibility(View.GONE); + mNotificationButton.setVisibility(View.VISIBLE); + } + + public void switchToNotificationMode() { + removeSettingsPanel(); + mSettingsButton.setVisibility(View.VISIBLE); + mNotificationScroller.setVisibility(View.VISIBLE); + mNotificationButton.setVisibility(View.INVISIBLE); + } + public boolean isInContentArea(int x, int y) { final int l = getPaddingLeft(); final int r = getWidth() - getPaddingRight(); @@ -40,5 +97,16 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel final int b = getHeight() - getPaddingBottom(); return x >= l && x < r && y >= t && y < b; } + + void removeSettingsPanel() { + if (mSettingsPanel != null) { + mSettingsFrame.removeViewAt(0); + mSettingsPanel = null; + } + } + + void addSettingsPanel() { + mSettingsPanel = View.inflate(getContext(), R.layout.sysbar_panel_settings, mSettingsFrame); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java new file mode 100644 index 0000000..744f667 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPeekPanel.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tablet; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.RelativeLayout; + +import com.android.systemui.R; + +public class NotificationPeekPanel extends RelativeLayout implements StatusBarPanel { + public NotificationPeekPanel(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public NotificationPeekPanel(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public boolean isInContentArea(int x, int y) { + final int l = getPaddingLeft(); + final int r = getWidth() - getPaddingRight(); + final int t = getPaddingTop(); + final int b = getHeight() - getPaddingBottom(); + return x >= l && x < r && y >= t && y < b; + } + +} + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsPanel.java new file mode 100644 index 0000000..9013f5c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsPanel.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tablet; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Slog; +import android.widget.LinearLayout; +import android.view.View; + +import com.android.systemui.R; + +public class SettingsPanel extends LinearLayout { + static final String TAG = "SettingsPanel"; + + public SettingsPanel(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SettingsPanel(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } +} + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 2efdf96..983215e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -99,7 +99,7 @@ public class TabletStatusBar extends StatusBar { InputMethodButton mInputMethodButton; NotificationPanel mNotificationPanel; - NotificationPanel mNotificationPeekWindow; + NotificationPeekPanel mNotificationPeekWindow; ViewGroup mNotificationPeekRow; int mNotificationPeekIndex; LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight; @@ -166,7 +166,7 @@ public class TabletStatusBar extends StatusBar { WindowManagerImpl.getDefault().addView(mNotificationPanel, lp); // Notification preview window - mNotificationPeekWindow = (NotificationPanel) View.inflate(context, + mNotificationPeekWindow = (NotificationPeekPanel) View.inflate(context, R.layout.sysbar_panel_notification_peek, null); mNotificationPeekRow = (ViewGroup) mNotificationPeekWindow.findViewById(R.id.content); mNotificationPeekWindow.setVisibility(View.GONE); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index e99b74f..18815f5 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -411,6 +411,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public final void openPanel(int featureId, KeyEvent event) { if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && mActionBar.isOverflowReserved()) { + // Invalidate the options menu, we want a prepare event that the app can respond to. + invalidatePanelMenu(FEATURE_OPTIONS_PANEL); mActionBar.showOverflowMenu(); } else { openPanel(getPanelState(featureId, true), event); @@ -1830,7 +1832,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback); - ActionMode mode = getCallback().onStartActionMode(wrappedCallback); + ActionMode mode = null; + try { + mode = getCallback().onWindowStartingActionMode(wrappedCallback); + } catch (AbstractMethodError ame) { + // Older apps might not implement this callback method. + } if (mode != null) { mActionMode = mode; } else { @@ -1874,6 +1881,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } } + if (mActionMode != null) { + try { + getCallback().onActionModeStarted(mActionMode); + } catch (AbstractMethodError ame) { + // Older apps might not implement this callback method. + } + } return mActionMode; } @@ -2089,6 +2103,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mActionModeView != null) { mActionModeView.removeAllViews(); } + try { + getCallback().onActionModeFinished(mActionMode); + } catch (AbstractMethodError ame) { + // Older apps might not implement this callback method. + } mActionMode = null; } } |