diff options
36 files changed, 919 insertions, 119 deletions
diff --git a/api/current.txt b/api/current.txt index 91fcab1e8a7d..45f02e201dc2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10965,6 +10965,7 @@ package android.hardware.camera2 { field public static final int LENS_FACING_FRONT = 0; // 0x0 field public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0; // 0x0 field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1 + field public static final int LENS_STATE_MOVING = 1; // 0x1 field public static final int LENS_STATE_STATIONARY = 0; // 0x0 field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1 field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2 @@ -10972,6 +10973,8 @@ package android.hardware.camera2 { field public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2; // 0x2 field public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0; // 0x0 field public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1; // 0x1 + field public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0; // 0x0 + field public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1; // 0x1 field public static final int STATISTICS_SCENE_FLICKER_50HZ = 1; // 0x1 field public static final int STATISTICS_SCENE_FLICKER_60HZ = 2; // 0x2 field public static final int STATISTICS_SCENE_FLICKER_NONE = 0; // 0x0 @@ -11077,6 +11080,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION; field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE; + field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE; field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE; field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN; field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_RED; @@ -25516,12 +25520,18 @@ package android.transition { public abstract class Transition implements java.lang.Cloneable { ctor public Transition(); method public android.transition.Transition addListener(android.transition.Transition.TransitionListener); + method public android.transition.Transition addTarget(int); method public android.transition.Transition addTarget(android.view.View); - method public android.transition.Transition addTargetId(int); method public abstract void captureEndValues(android.transition.TransitionValues); method public abstract void captureStartValues(android.transition.TransitionValues); method public android.transition.Transition clone(); method public android.animation.Animator createAnimator(android.view.ViewGroup, android.transition.TransitionValues, android.transition.TransitionValues); + method public android.transition.Transition excludeChildren(int, boolean); + method public android.transition.Transition excludeChildren(android.view.View, boolean); + method public android.transition.Transition excludeChildren(java.lang.Class, boolean); + method public android.transition.Transition excludeTarget(int, boolean); + method public android.transition.Transition excludeTarget(android.view.View, boolean); + method public android.transition.Transition excludeTarget(java.lang.Class, boolean); method public long getDuration(); method public android.animation.TimeInterpolator getInterpolator(); method public java.lang.String getName(); @@ -25531,8 +25541,8 @@ package android.transition { method public java.lang.String[] getTransitionProperties(); method public android.transition.TransitionValues getTransitionValues(android.view.View, boolean); method public android.transition.Transition removeListener(android.transition.Transition.TransitionListener); + method public android.transition.Transition removeTarget(int); method public android.transition.Transition removeTarget(android.view.View); - method public android.transition.Transition removeTargetId(int); method public android.transition.Transition setDuration(long); method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator); method public android.transition.Transition setStartDelay(long); diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 18fffc0a5d32..ec23f082f2f5 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -874,6 +874,20 @@ public abstract class CameraMetadata { public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2; // + // Enumeration values for CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE + // + + /** + * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE + */ + public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0; + + /** + * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE + */ + public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1; + + // // Enumeration values for CaptureRequest#TONEMAP_MODE // @@ -1119,6 +1133,11 @@ public abstract class CameraMetadata { */ public static final int LENS_STATE_STATIONARY = 0; + /** + * @see CaptureResult#LENS_STATE + */ + public static final int LENS_STATE_MOVING = 1; + // // Enumeration values for CaptureResult#STATISTICS_SCENE_FLICKER // diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index c3a636d1be6a..4608ab913fa7 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -957,6 +957,22 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p> + * Whether the HAL needs to output the lens + * shading map in output result metadata + * </p> + * <p> + * When set to ON, + * android.statistics.lensShadingMap must be provided in + * the output result metdata. + * </p> + * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF + * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON + */ + public static final Key<Integer> STATISTICS_LENS_SHADING_MAP_MODE = + new Key<Integer>("android.statistics.lensShadingMapMode", int.class); + + /** + * <p> * Table mapping blue input values to output * values * </p> diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index f83dad7e0871..3fcd2f9c147c 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -587,6 +587,7 @@ public final class CaptureResult extends CameraMetadata { * Current lens status * </p> * @see #LENS_STATE_STATIONARY + * @see #LENS_STATE_MOVING */ public static final Key<Integer> LENS_STATE = new Key<Integer>("android.lens.state", int.class); diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 8ea9d4873ba0..c588c6bf4c7a 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -29,6 +29,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewOverlay; import android.widget.ListView; +import android.widget.Spinner; import java.util.ArrayList; import java.util.List; @@ -100,6 +101,12 @@ public abstract class Transition implements Cloneable { TimeInterpolator mInterpolator = null; ArrayList<Integer> mTargetIds = new ArrayList<Integer>(); ArrayList<View> mTargets = new ArrayList<View>(); + ArrayList<Integer> mTargetIdExcludes = null; + ArrayList<View> mTargetExcludes = null; + ArrayList<Class> mTargetTypeExcludes = null; + ArrayList<Integer> mTargetIdChildExcludes = null; + ArrayList<View> mTargetChildExcludes = null; + ArrayList<Class> mTargetTypeChildExcludes = null; private TransitionValuesMaps mStartValues = new TransitionValuesMaps(); private TransitionValuesMaps mEndValues = new TransitionValuesMaps(); TransitionSet mParent = null; @@ -430,10 +437,8 @@ public abstract class Transition implements Cloneable { Log.d(LOG_TAG, " differing start/end values for view " + view); if (start == null || end == null) { - if (start == null) { - Log.d(LOG_TAG, " " + ((start == null) ? - "start null, end non-null" : "start non-null, end null")); - } + Log.d(LOG_TAG, " " + ((start == null) ? + "start null, end non-null" : "start non-null, end null")); } else { for (String key : start.values.keySet()) { Object startValue = start.values.get(key); @@ -504,6 +509,21 @@ public abstract class Transition implements Cloneable { * views are ignored and only the ids are used). */ boolean isValidTarget(View target, long targetId) { + if (mTargetIdExcludes != null && mTargetIdExcludes.contains(targetId)) { + return false; + } + if (mTargetExcludes != null && mTargetExcludes.contains(target)) { + return false; + } + if (mTargetTypeExcludes != null && target != null) { + int numTypes = mTargetTypeExcludes.size(); + for (int i = 0; i < numTypes; ++i) { + Class type = mTargetTypeExcludes.get(i); + if (type.isInstance(target)) { + return false; + } + } + } if (mTargetIds.size() == 0 && mTargets.size() == 0) { return true; } @@ -652,9 +672,9 @@ public abstract class Transition implements Cloneable { * @return The Transition to which the targetId is added. * Returning the same object makes it easier to chain calls during * construction, such as - * <code>transitionSet.addTransitions(new Fade()).addTargetId(someId);</code> + * <code>transitionSet.addTransitions(new Fade()).addTarget(someId);</code> */ - public Transition addTargetId(int targetId) { + public Transition addTarget(int targetId) { if (targetId > 0) { mTargetIds.add(targetId); } @@ -671,7 +691,7 @@ public abstract class Transition implements Cloneable { * construction, such as * <code>transitionSet.addTransitions(new Fade()).removeTargetId(someId);</code> */ - public Transition removeTargetId(int targetId) { + public Transition removeTarget(int targetId) { if (targetId > 0) { mTargetIds.remove(targetId); } @@ -679,6 +699,212 @@ public abstract class Transition implements Cloneable { } /** + * Whether to add the given id to the list of target ids to exclude from this + * transition. The <code>exclude</code> parameter specifies whether the target + * should be added to or removed from the excluded list. + * + * <p>Excluding targets is a general mechanism for allowing transitions to run on + * a view hierarchy while skipping target views that should not be part of + * the transition. For example, you may want to avoid animating children + * of a specific ListView or Spinner. Views can be excluded either by their + * id, or by their instance reference, or by the Class of that view + * (eg, {@link Spinner}).</p> + * + * @see #excludeChildren(int, boolean) + * @see #excludeTarget(View, boolean) + * @see #excludeTarget(Class, boolean) + * + * @param targetId The id of a target to ignore when running this transition. + * @param exclude Whether to add the target to or remove the target from the + * current list of excluded targets. + * @return This transition object. + */ + public Transition excludeTarget(int targetId, boolean exclude) { + mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude); + return this; + } + + /** + * Whether to add the children of the given id to the list of targets to exclude + * from this transition. The <code>exclude</code> parameter specifies whether + * the children of the target should be added to or removed from the excluded list. + * Excluding children in this way provides a simple mechanism for excluding all + * children of specific targets, rather than individually excluding each + * child individually. + * + * <p>Excluding targets is a general mechanism for allowing transitions to run on + * a view hierarchy while skipping target views that should not be part of + * the transition. For example, you may want to avoid animating children + * of a specific ListView or Spinner. Views can be excluded either by their + * id, or by their instance reference, or by the Class of that view + * (eg, {@link Spinner}).</p> + * + * @see #excludeTarget(int, boolean) + * @see #excludeChildren(View, boolean) + * @see #excludeChildren(Class, boolean) + * + * @param targetId The id of a target whose children should be ignored when running + * this transition. + * @param exclude Whether to add the target to or remove the target from the + * current list of excluded-child targets. + * @return This transition object. + */ + public Transition excludeChildren(int targetId, boolean exclude) { + mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude); + return this; + } + + /** + * Utility method to manage the boilerplate code that is the same whether we + * are excluding targets or their children. + */ + private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) { + if (targetId > 0) { + if (exclude) { + list = ArrayListManager.add(list, targetId); + } else { + list = ArrayListManager.remove(list, targetId); + } + } + return list; + } + + /** + * Whether to add the given target to the list of targets to exclude from this + * transition. The <code>exclude</code> parameter specifies whether the target + * should be added to or removed from the excluded list. + * + * <p>Excluding targets is a general mechanism for allowing transitions to run on + * a view hierarchy while skipping target views that should not be part of + * the transition. For example, you may want to avoid animating children + * of a specific ListView or Spinner. Views can be excluded either by their + * id, or by their instance reference, or by the Class of that view + * (eg, {@link Spinner}).</p> + * + * @see #excludeChildren(View, boolean) + * @see #excludeTarget(int, boolean) + * @see #excludeTarget(Class, boolean) + * + * @param target The target to ignore when running this transition. + * @param exclude Whether to add the target to or remove the target from the + * current list of excluded targets. + * @return This transition object. + */ + public Transition excludeTarget(View target, boolean exclude) { + mTargetExcludes = excludeView(mTargetExcludes, target, exclude); + return this; + } + + /** + * Whether to add the children of given target to the list of target children + * to exclude from this transition. The <code>exclude</code> parameter specifies + * whether the target should be added to or removed from the excluded list. + * + * <p>Excluding targets is a general mechanism for allowing transitions to run on + * a view hierarchy while skipping target views that should not be part of + * the transition. For example, you may want to avoid animating children + * of a specific ListView or Spinner. Views can be excluded either by their + * id, or by their instance reference, or by the Class of that view + * (eg, {@link Spinner}).</p> + * + * @see #excludeTarget(View, boolean) + * @see #excludeChildren(int, boolean) + * @see #excludeChildren(Class, boolean) + * + * @param target The target to ignore when running this transition. + * @param exclude Whether to add the target to or remove the target from the + * current list of excluded targets. + * @return This transition object. + */ + public Transition excludeChildren(View target, boolean exclude) { + mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude); + return this; + } + + /** + * Utility method to manage the boilerplate code that is the same whether we + * are excluding targets or their children. + */ + private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) { + if (target != null) { + if (exclude) { + list = ArrayListManager.add(list, target); + } else { + list = ArrayListManager.remove(list, target); + } + } + return list; + } + + /** + * Whether to add the given type to the list of types to exclude from this + * transition. The <code>exclude</code> parameter specifies whether the target + * type should be added to or removed from the excluded list. + * + * <p>Excluding targets is a general mechanism for allowing transitions to run on + * a view hierarchy while skipping target views that should not be part of + * the transition. For example, you may want to avoid animating children + * of a specific ListView or Spinner. Views can be excluded either by their + * id, or by their instance reference, or by the Class of that view + * (eg, {@link Spinner}).</p> + * + * @see #excludeChildren(Class, boolean) + * @see #excludeTarget(int, boolean) + * @see #excludeTarget(View, boolean) + * + * @param type The type to ignore when running this transition. + * @param exclude Whether to add the target type to or remove it from the + * current list of excluded target types. + * @return This transition object. + */ + public Transition excludeTarget(Class type, boolean exclude) { + mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude); + return this; + } + + /** + * Whether to add the given type to the list of types whose children should + * be excluded from this transition. The <code>exclude</code> parameter + * specifies whether the target type should be added to or removed from + * the excluded list. + * + * <p>Excluding targets is a general mechanism for allowing transitions to run on + * a view hierarchy while skipping target views that should not be part of + * the transition. For example, you may want to avoid animating children + * of a specific ListView or Spinner. Views can be excluded either by their + * id, or by their instance reference, or by the Class of that view + * (eg, {@link Spinner}).</p> + * + * @see #excludeTarget(Class, boolean) + * @see #excludeChildren(int, boolean) + * @see #excludeChildren(View, boolean) + * + * @param type The type to ignore when running this transition. + * @param exclude Whether to add the target type to or remove it from the + * current list of excluded target types. + * @return This transition object. + */ + public Transition excludeChildren(Class type, boolean exclude) { + mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude); + return this; + } + + /** + * Utility method to manage the boilerplate code that is the same whether we + * are excluding targets or their children. + */ + private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) { + if (type != null) { + if (exclude) { + list = ArrayListManager.add(list, type); + } else { + list = ArrayListManager.remove(list, type); + } + } + return list; + } + + /** * Sets the target view instances that this Transition is interested in * animating. By default, there are no targets, and a Transition will * listen for changes on every view in the hierarchy below the sceneRoot @@ -686,18 +912,18 @@ public abstract class Transition implements Cloneable { * the Transition to only listen for, and act on, these views. * All other views will be ignored. * - * <p>The target list is like the {@link #addTargetId(int) targetId} + * <p>The target list is like the {@link #addTarget(int) targetId} * list except this list specifies the actual View instances, not the ids * of the views. This is an important distinction when scene changes involve * view hierarchies which have been inflated separately; different views may * share the same id but not actually be the same instance. If the transition - * should treat those views as the same, then {@link #addTargetId(int)} should be used + * should treat those views as the same, then {@link #addTarget(int)} should be used * instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve * changes all within the same view hierarchy, among views which do not * necessarily have ids set on them, then the target list of views may be more * convenient.</p> * - * @see #addTargetId(int) + * @see #addTarget(int) * @param target A View on which the Transition will act, must be non-null. * @return The Transition to which the target is added. * Returning the same object makes it easier to chain calls during @@ -842,15 +1068,30 @@ public abstract class Transition implements Cloneable { // ignore listview children unless we can track them with stable IDs return; } - long id; + int id = View.NO_ID; + long itemId = View.NO_ID; if (!isListViewItem) { id = view.getId(); } else { ListView listview = (ListView) view.getParent(); int position = listview.getPositionForView(view); - id = listview.getItemIdAtPosition(position); + itemId = listview.getItemIdAtPosition(position); view.setHasTransientState(true); } + if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) { + return; + } + if (mTargetExcludes != null && mTargetExcludes.contains(view)) { + return; + } + if (mTargetTypeExcludes != null && view != null) { + int numTypes = mTargetTypeExcludes.size(); + for (int i = 0; i < numTypes; ++i) { + if (mTargetTypeExcludes.get(i).isInstance(view)) { + return; + } + } + } TransitionValues values = new TransitionValues(); values.view = view; captureStartValues(values); @@ -861,7 +1102,7 @@ public abstract class Transition implements Cloneable { mStartValues.idValues.put((int) id, values); } } else { - mStartValues.itemIdValues.put(id, values); + mStartValues.itemIdValues.put(itemId, values); } } else { if (!isListViewItem) { @@ -870,10 +1111,25 @@ public abstract class Transition implements Cloneable { mEndValues.idValues.put((int) id, values); } } else { - mEndValues.itemIdValues.put(id, values); + mEndValues.itemIdValues.put(itemId, values); } } if (view instanceof ViewGroup) { + // Don't traverse child hierarchy if there are any child-excludes on this view + if (mTargetIdChildExcludes != null && mTargetIdChildExcludes.contains(id)) { + return; + } + if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) { + return; + } + if (mTargetTypeChildExcludes != null && view != null) { + int numTypes = mTargetTypeChildExcludes.size(); + for (int i = 0; i < numTypes; ++i) { + if (mTargetTypeChildExcludes.get(i).isInstance(view)) { + return; + } + } + } ViewGroup parent = (ViewGroup) view; for (int i = 0; i < parent.getChildCount(); ++i) { captureHierarchy(parent.getChildAt(i), start); @@ -1356,4 +1612,51 @@ public abstract class Transition implements Cloneable { this.values = values; } } + + /** + * Utility class for managing typed ArrayLists efficiently. In particular, this + * can be useful for lists that we don't expect to be used often (eg, the exclude + * lists), so we'd like to keep them nulled out by default. This causes the code to + * become tedious, with constant null checks, code to allocate when necessary, + * and code to null out the reference when the list is empty. This class encapsulates + * all of that functionality into simple add()/remove() methods which perform the + * necessary checks, allocation/null-out as appropriate, and return the + * resulting list. + */ + private static class ArrayListManager { + + /** + * Add the specified item to the list, returning the resulting list. + * The returned list can either the be same list passed in or, if that + * list was null, the new list that was created. + * + * Note that the list holds unique items; if the item already exists in the + * list, the list is not modified. + */ + static <T> ArrayList<T> add(ArrayList<T> list, T item) { + if (list == null) { + list = new ArrayList<T>(); + } + if (!list.contains(item)) { + list.add(item); + } + return list; + } + + /** + * Remove the specified item from the list, returning the resulting list. + * The returned list can either the be same list passed in or, if that + * list becomes empty as a result of the remove(), the new list was created. + */ + static <T> ArrayList<T> remove(ArrayList<T> list, T item) { + if (list != null) { + list.remove(item); + if (list.isEmpty()) { + list = null; + } + } + return list; + } + } + } diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java index ebedeeb4fa73..eeb6cba7c68e 100644 --- a/core/java/android/transition/TransitionInflater.java +++ b/core/java/android/transition/TransitionInflater.java @@ -235,7 +235,7 @@ public class TransitionInflater { int numTargets = targetIds.size(); if (numTargets > 0) { for (int i = 0; i < numTargets; ++i) { - transition.addTargetId(targetIds.get(i)); + transition.addTarget(targetIds.get(i)); } } } diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java index 1972c2a56ae3..f72b36e3e243 100644 --- a/core/java/android/transition/TransitionSet.java +++ b/core/java/android/transition/TransitionSet.java @@ -155,8 +155,8 @@ public class TransitionSet extends Transition { } @Override - public TransitionSet addTargetId(int targetId) { - return (TransitionSet) super.addTargetId(targetId); + public TransitionSet addTarget(int targetId) { + return (TransitionSet) super.addTarget(targetId); } @Override @@ -165,8 +165,8 @@ public class TransitionSet extends Transition { } @Override - public TransitionSet removeTargetId(int targetId) { - return (TransitionSet) super.removeTargetId(targetId); + public TransitionSet removeTarget(int targetId) { + return (TransitionSet) super.removeTarget(targetId); } @Override @@ -278,9 +278,11 @@ public class TransitionSet extends Transition { @Override public void captureStartValues(TransitionValues transitionValues) { int targetId = transitionValues.view.getId(); - for (Transition childTransition : mTransitions) { - if (childTransition.isValidTarget(transitionValues.view, targetId)) { - childTransition.captureStartValues(transitionValues); + if (isValidTarget(transitionValues.view, targetId)) { + for (Transition childTransition : mTransitions) { + if (childTransition.isValidTarget(transitionValues.view, targetId)) { + childTransition.captureStartValues(transitionValues); + } } } } @@ -288,9 +290,11 @@ public class TransitionSet extends Transition { @Override public void captureEndValues(TransitionValues transitionValues) { int targetId = transitionValues.view.getId(); - for (Transition childTransition : mTransitions) { - if (childTransition.isValidTarget(transitionValues.view, targetId)) { - childTransition.captureEndValues(transitionValues); + if (isValidTarget(transitionValues.view, targetId)) { + for (Transition childTransition : mTransitions) { + if (childTransition.isValidTarget(transitionValues.view, targetId)) { + childTransition.captureEndValues(transitionValues); + } } } } diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index 68c3d0ae2a47..0c2e7211fd11 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -375,6 +375,10 @@ public class ActionMenuPresenter extends BaseMenuPresenter return mOverflowPopup != null && mOverflowPopup.isShowing(); } + public boolean isOverflowMenuShowPending() { + return mPostedOpenRunnable != null || isOverflowMenuShowing(); + } + /** * @return true if space has been reserved in the action menu for an overflow item. */ diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java index ca7f5d03b1bf..f3891c7577c5 100644 --- a/core/java/com/android/internal/widget/AbsActionBarView.java +++ b/core/java/com/android/internal/widget/AbsActionBarView.java @@ -201,6 +201,13 @@ public abstract class AbsActionBarView extends ViewGroup { return false; } + public boolean isOverflowMenuShowPending() { + if (mActionMenuPresenter != null) { + return mActionMenuPresenter.isOverflowMenuShowPending(); + } + return false; + } + public boolean isOverflowReserved() { return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved(); } diff --git a/core/res/res/drawable-xhdpi/default_wallpaper.jpg b/core/res/res/drawable-xhdpi/default_wallpaper.jpg Binary files differdeleted file mode 100644 index da9fa91fae70..000000000000 --- a/core/res/res/drawable-xhdpi/default_wallpaper.jpg +++ /dev/null diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 7ddf2e9fbb23..4a26a05dd52d 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4544,7 +4544,7 @@ </declare-styleable> <!-- Use <code>target</code> as the root tag of the XML resource that - describes a {@link android.transition.Transition#addTargetId(int) + describes a {@link android.transition.Transition#addTarget(int) targetId} of a transition. There can be one or more targets inside a <code>targets</code> tag, which is itself inside an appropriate {@link android.R.styleable#Transition Transition} tag. diff --git a/docs/downloads/training/LocationProvider.zip b/docs/downloads/training/LocationProvider.zip Binary files differnew file mode 100644 index 000000000000..d5ee311ed4fb --- /dev/null +++ b/docs/downloads/training/LocationProvider.zip diff --git a/docs/html/training/location/activity-recognition.jd b/docs/html/training/location/activity-recognition.jd index 47ba5f8ab490..d50064b00d6e 100644 --- a/docs/html/training/location/activity-recognition.jd +++ b/docs/html/training/location/activity-recognition.jd @@ -31,13 +31,13 @@ trainingnavtop=true </div> <p> - This lesson shows you how to request activity recognition updates from Location Services. Activity recognition tries to detect the user's current physical activity, such as walking, driving, or standing still. Requests for updates go through an activity recognition client, which, while different from the location client used by location or geofencing, follows a similar pattern. Based on the update interval you choose, Location Services sends out activity information containing one or more possible activities and the confidence level for - each one. + each one. This lesson shows you how to request activity recognition updates from Location + Services. </p> <h2 id="RequestUpdates">Request Activity Recognition Updates</h2> <p> diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd index 5ebbb84f69e6..e03eac666554 100644 --- a/docs/html/training/location/index.jd +++ b/docs/html/training/location/index.jd @@ -85,4 +85,12 @@ startpage=true Learn how to recognize the user's current activity, such as walking, bicycling, or driving a car, and how to use this information to modify your app's location strategy. </dd> + <dt> + <b><a href="location-testing.html">Testing Using Mock Locations</a></b> + </dt> + <dd> + Learn how to test a location-aware app by injecting mock locations into Location + Services. In mock mode, Location Services sends out mock locations that you inject instead + of sensor-based locations. + </dd> </dl> diff --git a/docs/html/training/location/location-testing.jd b/docs/html/training/location/location-testing.jd new file mode 100644 index 000000000000..e36bac13621e --- /dev/null +++ b/docs/html/training/location/location-testing.jd @@ -0,0 +1,371 @@ +page.title=Testing Using Mock Locations + +trainingnavtop=true +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- table of contents --> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#TurnOnMockMode">Turn On Mock Mode</a></li> + <li><a href="#SendMockLocations">Send Mock Locations</a></li> + <li><a href="RunProvider">Run the Mock Location Provider App</a></li> + <li><a href="#TestingTips">Testing Tips</a> +</ol> + +<h2>You should also read</h2> +<ul> + <li><a href="receive-location-updates.html">Receiving Location Updates</a></li> + <li><a href="geofencing.html">Creating and Monitoring Geofences</a></li> + <li><a href="{@docRoot}guide/components/services.html">Services</a></li> + <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a> +</ul> + +<h2>Example Test App</h2> + +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/LocationProvider.zip" class="button" + >Download the sample</a> + <p class="filename">LocationProvider.zip</p> +</div> + +</div> +</div> +<p> + To test a location-aware app that uses Location Services, you don't need to move your device + from place to place to generate location data. Instead, you can put Location Services into mock + mode. In this mode, you can send mock {@link android.location.Location} objects to + Location Services, which then sends them to location clients. In mock mode, Location Services + also uses mock {@link android.location.Location} objects to trigger geofences. +</p> +<p> + Using mock locations has several advantages: +</p> +<ul> + <li> + Mock locations allow you to create specific mock data, instead of trying to approximate + data by moving an actual device. + </li> + <li> + Since mock locations come from Location Services, they test every part of your + location-handling code. In addition, since you can send the mock data from outside your + production app, you don't have to disable or remove test code before you publish. + </li> + <li> + Since you don't have to generate test locations by moving a device, you can test an app + using the emulator. + </li> +</ul> +<p> + The best way to use mock locations is to send them from a separate mock location provider app. + This lesson includes a provider app that you can download and use to test your own software. + Modify the provider app as necessary to suit your own needs. Some ideas for providing test data + to the app are listed in the section <a href="TestData">Managing test data</a>. +</p> +<p> + The remainder of this lesson shows you how to turn on mock mode and use a location client to + send mock locations to Location Services. +</p> +<p class="note"> + <strong>Note:</strong> Mock locations have no effect on the activity recognition algorithm used + by Location Services. To learn more about activity recognition, see the lesson + <a href="activity-recognition.html">Recognizing the User's Current Activity</a>. +</p> +<!-- + Create a Test App + --> +<h2 id="TurnOnMockMode">Turn On Mock Mode</h2> +<p> + To send mock locations to Location Services in mock mode, a test app must request the permission + {@link android.Manifest.permission#ACCESS_MOCK_LOCATION}. In addition, you must enable mock + locations on the test device using the option <b>Enable mock locations</b>. To learn how to + enable mock locations on the device, see + <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>. +</p> +<p> + To turn on mock mode in Location Services, start by connecting a location client to Location + Services, as described in the lesson + <a href="retrieve-current.html">Retrieving the Current Location</a>. + Next, call the method +<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>. + Once you call this method, Location Services turns off its internal location providers and only + sends out the mock locations you provide it. The following snippet shows you how to call +<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>: +</p> +<pre> + // Define a LocationClient object + public LocationClient mLocationClient; + ... + // Connect to Location Services + mLocationClient.connect(); + ... + // When the location client is connected, set mock mode + mLocationClinet.setMockMode(true); +</pre> +<p> + Once you have connected the location client to Location Services, you must keep it connected + until you finish sending out mock locations. Once you call +<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#disconnect()">LocationClient.disconnect()</a></code>, + Location Services returns to using its internal location providers. To turn off mock mode while + the location client is connected, call +<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(false)</a></code>. +</p> +<h2 id="SendMockLocations">Send Mock Locations</h2> +<p> + Once you have set mock mode, you can create mock {@link android.location.Location} objects and + send them to Location Services. In turn, Location Services sends these mock + {@link android.location.Location} objects to connected location clients. Location Services also + uses the mock {@link android.location.Location} objects to control geofence triggering. +</p> +<p> + To create a new mock {@link android.location.Location}, create a new + {@link android.location.Location} object using your test data. Always set the provider + value to {@code flp}, which is the code that Location Services puts into the + {@link android.location.Location} objects it sends out. The following snippet shows you how + to create a new mock {@link android.location.Location}: +</p> +<pre> + private static final String PROVIDER = "flp"; + private static final double LAT = 37.377166; + private static final double LNG = -122.086966; + private static final float ACCURACY = 3.0f; + ... + /* + * From input arguments, create a single Location with provider set to + * "flp" + */ + public Location createLocation(double lat, double lng, float accuracy) { + // Create a new Location + Location newLocation = new Location(PROVIDER); + newLocation.setLatitude(lat); + newLocation.setLongitude(lng); + newLocation.setAccuracy(accuracy); + return newLocation; + } + ... + // Example of creating a new Location from test data + Location testLocation = createLocation(LAT, LNG, ACCURACY); +</pre> +<p> + In mock mode, to send a mock location to Location Services call the method +<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockLocation(android.location.Location)">LocationClient.setMockLocation()</a></code>. + For example: +</p> +<pre> + mLocationClient.setMockLocation(testLocation); +</pre> +<p> + Location Services sets this mock location as the current location, and this location is sent + out as the next location update. If this new mock location moves across a geofence boundary, + Location Services triggers the geofence. +</p> +<!-- + Run the Mock Location Provider + --> +<h2 id="RunProvider">Run the Mock Location Provider App</h2> +<p> + This section contains a brief overview of the mock location provider sample app + (available for download above) and gives you directions for testing an app using the sample app. +</p> +<h3>Overview</h3> +<p> + The mock location provider app included with this lesson sends mock + {@link android.location.Location} objects to Location Services from a background thread running + in a started {@link android.app.Service}. By using a started service, the provider app is able + to keep running even if the app's main {@link android.app.Activity} is destroyed because of + a configuration change or other system event. By using a background thread, the service is able + to perform a long-running test without blocking the UI thread. +</p> +<p> + The {@link android.app.Activity} that starts when you run the provider app allows you to + send test parameters to the {@link android.app.Service} and control the type of test you want. + You have the following options: +</p> +<dl> + <dt> + Pause before test + </dt> + <dd> + The number of seconds to wait before the provider app starts sending test data to Location + Services. This interval allows you to switch from the provider app to the app under test + before the testing actually starts. + </dd> + <dt> + Send interval + </dt> + <dd> + The number of seconds that the provider app waits before it sends another mock location to + Location Services. See the section <a href="#TestingTips">Testing Tips</a> to learn more + about setting the send interval. + </dd> + <dt> + Run once + </dt> + <dd> + Switch from normal mode to mock mode, run through the test data once, switch back to + normal mode, and then kill the {@link android.app.Service}. + </dd> + <dt> + Run continuously + </dt> + <dd> + Switch from normal mode to mock mode, then run through the test data indefinitely. The + background thread and the started {@link android.app.Service} continue to run, even if the + main {@link android.app.Activity} is destroyed. + </dd> + <dt> + Stop test + </dt> + <dd> + If a continuous test is in progress, stop it; otherwise, return a warning message. The + started {@link android.app.Service} switches from mock mode to normal mode and then + stops itself. This also stops the background thread. + </dd> +</dl> +<p> + Besides the options, the provider app has two status displays: +</p> +<dl> + <dt> + App status + </dt> + <dd> + Displays messages related to the lifecycle of the provider app. + </dd> + <dt> + Connection status + </dt> + <dd> + Displays messages related to the state of the location client connection. + </dd> +</dl> +<p> + While the started {@link android.app.Service} is running, it also posts notifications with the + testing status. These notifications allow you to see status updates even if the app is not in + the foreground. When you click on a notification, the main {@link android.app.Activity} of the + provider app returns to the foreground. +</p> +<h3>Test using the mock location provider app</h3> +<p> + To test mock location data coming from the mock location provider app: +</p> +<ol> + <li> + Install the mock location provider app on a device that has Google Play services installed. + Location Services is part of Google Play services. + </li> + <li> + On the device, enable mock locations. To learn how to do this, see the topic + <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>. + </li> + <li> + Start the provider app from the Launcher, then choose the options you want from the main + screen. + </li> + <li> + Unless you've removed the pause interval feature, the mock location provider app + pauses for a few seconds, and then starts sending mock location data to Location + Services. + </li> + <li> + Run the app you want to test. While the mock location provider app is running, the app + you're testing receives mock locations instead of real locations. + </li> + <li> + If the provider app is in the midst of a continuous test, you can switch back to real + locations by clicking <b>Stop test</b>. This forces the started {@link android.app.Service} + to turn off mock mode and then stop itself. When the service stops itself, the background + thread is also destroyed. + </li> + +</ol> +<h2 id="TestingTips">Testing Tips</h2> +<p> + The following sections contain tips for creating mock location data and using the data with a + mock location provider app. +</p> +<h3>Choosing a send interval</h3> +<p> + Each location provider that contributes to the fused location sent out by Location Services has + its own minimum update cycle. For example, the GPS provider can't send a new location more often + than once per second, and the Wi-Fi provider can't send a new location more often than once + every five seconds. These cycle times are handled automatically for real locations, but you + should account for them when you send mock locations. For example, you shouldn't send a new mock + location more than once per second. If you're testing indoor locations, which rely heavily on + the Wi-Fi provider, then you should consider using a send interval of five seconds. +</p> +<h3>Simulating speed</h3> +<p> + To simulate the speed of an actual device, shorten or lengthen the distance between two + successive locations. For example, changing the location by 88 feet every second simulates + car travel, because this change works out to 60 miles an hour. In comparison, changing the + location by 1.5 feet every second simulates brisk walking, because this change works out to + 3 miles per hour. +</p> +<h3>Calculating location data</h3> +<p> + By searching the web, you can find a variety of small programs that calculate a new set of + latitude and longitude coordinates from a starting location and a distance, as well as + references to formulas for calculating the distance between two points based on their latitude + and longitude. In addition, the {@link android.location.Location} class offers two methods for + calculating the distance between points: +</p> +<dl> + <dt> + {@link android.location.Location#distanceBetween distanceBetween()} + </dt> + <dd> + A static method that calculates the distance between two points specified by latitude and + longitude. + </dd> + <dt> + {@link android.location.Location#distanceTo distanceTo()} + </dt> + <dd> + For a given {@link android.location.Location}, returns the distance to another + {@link android.location.Location}. + </dd> +</dl> +<h3>Geofence testing</h3> +<p> + When you test an app that uses geofence detection, use test data that reflects different modes + of travel, including walking, cycling, driving, and traveling by train. For a slow mode of + travel, make small changes in position between points. Conversely, for a fast mode of travel, + make a large change in position between points. +</p> +<h3 id="TestData">Managing test data</h3> +<p> + The mock location provider app included with this lesson contains test latitude, longitude, + and accuracy values in the form of constants. You may want to consider other ways of organizing + data as well: +</p> +<dl> + <dt> + XML + </dt> + <dd> + Store location data in XML files that are including in the provider app. By separating the + data from the code, you facilitate changes to the data. + </dd> + <dt> + Server download + </dt> + <dd> + Store location data on a server and then have the provider app download it. Since the data + is completely separate from the app, you can change the data without having to rebuild the + app. You can also change the data on the server and have the changes reflected immediately + in the mock locations you're testing. + </dd> + <dt> + Recorded data + </dt> + <dd> + Instead of making up test data, write a utility app that records location data as you move + the device. Use the recorded data as your test data, or use the data to guide you in + developing test data. For example, record locations as you walk with a device, and then + create mock locations that have an appropriate change in latitude and longitude over + time. + </dd> +</dl> diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index ebf553cc501b..0c4f9df72967 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -631,6 +631,10 @@ include the action bar on devices running Android 2.1 or higher." Recognizing the User's Current Activity </a> </li> + <li><a href="<?cs var:toroot ?>training/location/location-testing.html"> + Testing Using Mock Locations + </a> + </li> </ul> </li> </ul> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 344446f14bdd..7b09092508ad 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -137,6 +137,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { static class Network { String ssid = ""; // equals() and hashCode() need these to be non-null String key_mgmt = ""; + boolean certUsed = false; final ArrayList<String> rawLines = new ArrayList<String>(); public static Network readFromStream(BufferedReader in) { @@ -167,6 +168,12 @@ public class SettingsBackupAgent extends BackupAgentHelper { ssid = line; } else if (line.startsWith("key_mgmt")) { key_mgmt = line; + } else if (line.startsWith("client_cert=")) { + certUsed = true; + } else if (line.startsWith("ca_cert=")) { + certUsed = true; + } else if (line.startsWith("ca_path=")) { + certUsed = true; } } @@ -246,6 +253,13 @@ public class SettingsBackupAgent extends BackupAgentHelper { public void write(Writer w) throws IOException { for (Network net : mNetworks) { + if (net.certUsed) { + // Networks that use certificates for authentication can't be restored + // because the certificates they need don't get restored (because they + // are stored in keystore, and can't be restored) + continue; + } + net.write(w); } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index a3bd785772a8..11913ee5ee4a 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -22,6 +22,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.*; +import android.view.ViewConfiguration; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; import com.android.internal.view.menu.ContextMenuBuilder; @@ -540,7 +541,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void openPanel(int featureId, KeyEvent event) { if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && - mActionBar.isOverflowReserved()) { + mActionBar.isOverflowReserved() && + !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) { if (mActionBar.getVisibility() == View.VISIBLE) { mActionBar.showOverflowMenu(); } @@ -549,7 +551,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - private void openPanel(PanelFeatureState st, KeyEvent event) { + private void openPanel(final PanelFeatureState st, KeyEvent event) { // System.out.println("Open panel: isOpen=" + st.isOpen); // Already open, return @@ -673,7 +675,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void closePanel(int featureId) { if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && - mActionBar.isOverflowReserved()) { + mActionBar.isOverflowReserved() && + !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) { mActionBar.hideOverflowMenu(); } else if (featureId == FEATURE_CONTEXT_MENU) { closeContextMenu(); @@ -836,7 +839,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean playSoundEffect = false; final PanelFeatureState st = getPanelState(featureId, true); if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && - mActionBar.isOverflowReserved()) { + mActionBar.isOverflowReserved() && + !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) { if (mActionBar.getVisibility() == View.VISIBLE) { if (!mActionBar.isOverflowMenuShowing()) { if (!isDestroyed() && preparePanel(st, event)) { @@ -1014,7 +1018,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private void reopenMenu(boolean toggleMenuMode) { - if (mActionBar != null && mActionBar.isOverflowReserved()) { + if (mActionBar != null && mActionBar.isOverflowReserved() && + (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() || + mActionBar.isOverflowMenuShowPending())) { final Callback cb = getCallback(); if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) { if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) { diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java index c215f40075ca..ed2b8fd86d9a 100644 --- a/services/java/com/android/server/wifi/WifiService.java +++ b/services/java/com/android/server/wifi/WifiService.java @@ -325,11 +325,13 @@ public final class WifiService extends IWifiManager.Stub { private class BatchedScanRequest extends DeathRecipient { BatchedScanSettings settings; int uid; + int pid; - BatchedScanRequest(BatchedScanSettings settings, IBinder binder, int uid) { + BatchedScanRequest(BatchedScanSettings settings, IBinder binder) { super(0, null, binder, null); this.settings = settings; - this.uid = uid; + this.uid = getCallingUid(); + this.pid = getCallingPid(); } public void binderDied() { stopBatchedScan(settings, mBinder); @@ -337,6 +339,10 @@ public final class WifiService extends IWifiManager.Stub { public String toString() { return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}"; } + + public boolean isSameApp() { + return (this.uid == getCallingUid() && this.pid == getCallingPid()); + } } private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>(); @@ -359,7 +365,7 @@ public final class WifiService extends IWifiManager.Stub { if (mBatchedScanSupported == false) return false; requested = new BatchedScanSettings(requested); if (requested.isInvalid()) return false; - BatchedScanRequest r = new BatchedScanRequest(requested, binder, Binder.getCallingUid()); + BatchedScanRequest r = new BatchedScanRequest(requested, binder); synchronized(mBatchedScanners) { mBatchedScanners.add(r); resolveBatchedScannersLocked(); @@ -393,16 +399,18 @@ public final class WifiService extends IWifiManager.Stub { public void stopBatchedScan(BatchedScanSettings settings, IBinder binder) { enforceChangePermission(); if (mBatchedScanSupported == false) return; + ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>(); synchronized(mBatchedScanners) { - BatchedScanRequest found = null; for (BatchedScanRequest r : mBatchedScanners) { - if (r.mBinder.equals(binder) && r.settings.equals(settings)) { - found = r; - break; + if (r.isSameApp() && (settings == null || settings.equals(r.settings))) { + found.add(r); + if (settings != null) break; } } - if (found != null) { - mBatchedScanners.remove(found); + for (BatchedScanRequest r : found) { + mBatchedScanners.remove(r); + } + if (found.size() != 0) { resolveBatchedScannersLocked(); } } diff --git a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java index 482dc051afb5..f687da37eedf 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java +++ b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java @@ -76,10 +76,10 @@ public class ContactsExpansion extends Activity { final TransitionSet myTransition = new TransitionSet(); myTransition.addTransition(new Fade(Fade.IN)). - addTransition(new Rotate().addTargetId(R.id.contact_arrow)). + addTransition(new Rotate().addTarget(R.id.contact_arrow)). addTransition(new ChangeBounds()). addTransition(new Fade(Fade.OUT)). - addTransition(new Crossfade().addTargetId(R.id.contact_picture)); + addTransition(new Crossfade().addTarget(R.id.contact_picture)); final ToggleScene toggleScene = new ToggleScene(container, myTransition); contactItem.setOnClickListener(new View.OnClickListener() { @Override diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java index eb799ec4e867..5bb0e77c08c9 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java +++ b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java @@ -47,8 +47,8 @@ public class CrossFadeDemo extends Activity { Crossfade crossfade = new Crossfade(); crossfade.setFadeBehavior(Crossfade.FADE_BEHAVIOR_CROSSFADE); crossfade.setResizeBehavior(Crossfade.RESIZE_BEHAVIOR_NONE); - crossfade.addTargetId(R.id.textview).addTargetId(R.id.textview1). - addTargetId(R.id.textview2); + crossfade.addTarget(R.id.textview).addTarget(R.id.textview1). + addTarget(R.id.textview2); mTransitionManager = new TransitionManager(); TransitionSet moveCrossFade = new TransitionSet(); moveCrossFade.addTransition(crossfade).addTransition(new ChangeBounds()); diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java index 09b495fecf48..1f278b9a6485 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java +++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java @@ -48,7 +48,7 @@ public class CrossfadeImage extends Activity { mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); Crossfade mCrossfade = new Crossfade(); - mCrossfade.addTargetId(R.id.contact_picture); + mCrossfade.addTarget(R.id.contact_picture); TransitionSet group = new TransitionSet(); group.setDuration(1500); diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java index c11839879b18..d784f75f546c 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java +++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java @@ -57,7 +57,7 @@ public class CrossfadeMultiple extends Activity { mTextView = (TextView) findViewById(R.id.textview); mCrossfade = new Crossfade(); - mCrossfade.addTargetId(R.id.button).addTargetId(R.id.textview).addTargetId(R.id.imageview); + mCrossfade.addTarget(R.id.button).addTarget(R.id.textview).addTarget(R.id.imageview); mCrossfadeGroup = new TransitionSet(); mCrossfadeGroup.setDuration(300); diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo1.java b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java index 5c0cd45c0426..5b5eb156bba0 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/Demo1.java +++ b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java @@ -70,9 +70,9 @@ public class Demo1 extends Activity { if (mFirstTime) { mFirstTime = false; TransitionSet transition = new TransitionSet(); - transition.addTransition(new Fade().addTargetId(R.id.resultsText). - addTargetId(R.id.resultsList)). - addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)); + transition.addTransition(new Fade().addTarget(R.id.resultsText). + addTarget(R.id.resultsList)). + addTransition(new ChangeBounds().addTarget(R.id.searchContainer)); mTransitionManager = new TransitionManager(); mTransitionManager.setTransition(mSearchScreen, transition); mTransitionManager.setTransition(mResultsScreen, transition); diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo2.java b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java index 334b777851b1..0f3257bbadad 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/Demo2.java +++ b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java @@ -57,10 +57,10 @@ public class Demo2 extends Activity { } TransitionSet transition = new TransitionSet(); - transition.addTransition(new Fade().addTargetId(R.id.resultsText). - addTargetId(R.id.resultsList)). - addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)). - addTransition(new Recolor().addTargetId(R.id.container)); + transition.addTransition(new Fade().addTarget(R.id.resultsText). + addTarget(R.id.resultsList)). + addTransition(new ChangeBounds().addTarget(R.id.searchContainer)). + addTransition(new Recolor().addTarget(R.id.container)); mTransitionManager = new TransitionManager(); mTransitionManager.setTransition(mSearchScreen, transition); mTransitionManager.setTransition(mResultsScreen, transition); diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo4.java b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java index d1c33586fc2e..3aadbb0ae670 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/Demo4.java +++ b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java @@ -46,17 +46,17 @@ public class Demo4 extends Activity { TransitionSet transitionToResults = new TransitionSet(); Fade fade = new Fade(); - fade.addTargetId(R.id.resultsText).addTargetId(R.id.resultsList); + fade.addTarget(R.id.resultsText).addTarget(R.id.resultsList); fade.setStartDelay(300); fade.setDuration(1000); transitionToResults.addTransition(fade). - addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)). - addTransition(new Recolor().addTargetId(R.id.container)); + addTransition(new ChangeBounds().addTarget(R.id.searchContainer)). + addTransition(new Recolor().addTarget(R.id.container)); TransitionSet transitionToSearch = new TransitionSet(); transitionToSearch.addTransition(fade). - addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)). - addTransition(new Recolor().addTargetId(R.id.container)); + addTransition(new ChangeBounds().addTarget(R.id.searchContainer)). + addTransition(new Recolor().addTarget(R.id.container)); mTransitionManager = new TransitionManager(); mTransitionManager.setTransition(mSearchScreen, transitionToSearch); diff --git a/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java index 000ea9b10b92..29fb868794f4 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java +++ b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java @@ -34,8 +34,8 @@ public class FadingTest extends Activity { Scene mCurrentScene; static { - sFade.addTargetId(R.id.removingButton).addTargetId(R.id.invisibleButton). - addTargetId(R.id.goneButton); + sFade.addTarget(R.id.removingButton).addTarget(R.id.invisibleButton). + addTarget(R.id.goneButton); } @Override diff --git a/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java b/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java index 70257bb28f9d..c26e93f95ed3 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java +++ b/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java @@ -53,9 +53,9 @@ public class InterruptionTest extends Activity { mScene4RB = (RadioButton) findViewById(R.id.scene4RB); ChangeBounds changeBounds1 = new ChangeBounds(); - changeBounds1.addTargetId(R.id.button); + changeBounds1.addTarget(R.id.button); ChangeBounds changeBounds2 = new ChangeBounds(); - changeBounds2.addTargetId(R.id.button1); + changeBounds2.addTarget(R.id.button1); mSequencedMove.addTransition(changeBounds1).addTransition(changeBounds2); mSequencedMove.setDuration(1000); diff --git a/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java index 34ec6ccf4ab9..92bbb85edb52 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java +++ b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java @@ -54,9 +54,9 @@ public class LoginActivity extends Activity { // Custom transitions in/out of NewUser screen - slide in the 2nd password UI TransitionSet slider = new TransitionSet(); - slider.addTransition(new Slide().addTargetId(R.id.retype).addTargetId(R.id.retypeEdit)); - slider.addTransition(new Recolor().addTargetId(R.id.password). - addTargetId(R.id.passwordEdit)); + slider.addTransition(new Slide().addTarget(R.id.retype).addTarget(R.id.retypeEdit)); + slider.addTransition(new Recolor().addTarget(R.id.password). + addTarget(R.id.passwordEdit)); slider.addTransition(new Fade()); mTransitionManager.setTransition(mLoginScene, mNewUserScene, slider); mTransitionManager.setTransition(mPasswordScene, mNewUserScene, slider); @@ -64,8 +64,8 @@ public class LoginActivity extends Activity { mTransitionManager.setTransition(mNewUserScene, mPasswordScene, slider); // Custom transitions with recoloring password field - Transition colorizer = new Recolor().addTargetId(R.id.password). - addTargetId(R.id.passwordEdit); + Transition colorizer = new Recolor().addTarget(R.id.password). + addTarget(R.id.passwordEdit); mTransitionManager.setTransition(mLoginScene, mPasswordScene, colorizer); mTransitionManager.setTransition(mPasswordScene, mLoginScene, colorizer); diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java index c6011f25ecb9..ecf5ef349c25 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java +++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java @@ -47,17 +47,17 @@ public class ScenesTestv21 extends Activity { TransitionSet transitionToResults = new TransitionSet(); Fade fade = new Fade(); - fade.addTargetId(R.id.resultsText).addTargetId(R.id.resultsList); + fade.addTarget(R.id.resultsText).addTarget(R.id.resultsList); fade.setStartDelay(300); transitionToResults.addTransition(fade); - transitionToResults.addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)); - transitionToResults.addTransition(new Recolor().addTargetId(R.id.container)); + transitionToResults.addTransition(new ChangeBounds().addTarget(R.id.searchContainer)); + transitionToResults.addTransition(new Recolor().addTarget(R.id.container)); TransitionSet transitionToSearch = new TransitionSet(); - transitionToSearch.addTransition(new Fade().addTargetId(R.id.resultsText). - addTargetId(R.id.resultsList)); - transitionToSearch.addTransition(new ChangeBounds().addTargetId(R.id.searchContainer)); - transitionToSearch.addTransition(new Recolor().addTargetId(R.id.container)); + transitionToSearch.addTransition(new Fade().addTarget(R.id.resultsText). + addTarget(R.id.resultsList)); + transitionToSearch.addTransition(new ChangeBounds().addTarget(R.id.searchContainer)); + transitionToSearch.addTransition(new Recolor().addTarget(R.id.container)); mTransitionManager = new TransitionManager(); mTransitionManager.setTransition(mSearchScreen, transitionToSearch); mTransitionManager.setTransition(mResultsScreen, transitionToResults); diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java index ab1dc263831d..c550e92f62d6 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java +++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java @@ -51,9 +51,9 @@ public class SequenceTest extends Activity { mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test, this); mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.fading_test_scene_2, this); - Transition fade1 = new Fade().addTargetId(R.id.removingButton); - Transition fade2 = new Fade().addTargetId(R.id.invisibleButton); - Transition fade3 = new Fade().addTargetId(R.id.goneButton); + Transition fade1 = new Fade().addTarget(R.id.removingButton); + Transition fade2 = new Fade().addTarget(R.id.invisibleButton); + Transition fade3 = new Fade().addTarget(R.id.goneButton); TransitionSet fader = new TransitionSet(). setOrdering(TransitionSet.ORDERING_SEQUENTIAL); fader.addTransition(fade1).addTransition(fade2).addTransition(fade3). diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java index 52c21c99e515..92b169ec9e1f 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java +++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java @@ -52,14 +52,14 @@ public class SequenceTestSimple extends Activity { TransitionSet fader = new TransitionSet(). setOrdering(TransitionSet.ORDERING_SEQUENTIAL); - fader.addTransition(new Fade().addTargetId(R.id.removingButton)); - fader.addTransition(new ChangeBounds().addTargetId(R.id.sceneSwitchButton)); + fader.addTransition(new Fade().addTarget(R.id.removingButton)); + fader.addTransition(new ChangeBounds().addTarget(R.id.sceneSwitchButton)); sequencedFade = fader; sequencedFadeReverse = new TransitionSet(). setOrdering(TransitionSet.ORDERING_SEQUENTIAL); - sequencedFadeReverse.addTransition(new ChangeBounds().addTargetId(R.id.sceneSwitchButton)); - sequencedFadeReverse.addTransition(new Fade().addTargetId(R.id.removingButton)); + sequencedFadeReverse.addTransition(new ChangeBounds().addTarget(R.id.sceneSwitchButton)); + sequencedFadeReverse.addTransition(new Fade().addTarget(R.id.removingButton)); mCurrentScene = mScene1; } diff --git a/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java index 05af0440149c..9b246adb08cb 100644 --- a/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java +++ b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java @@ -67,8 +67,8 @@ public class SurfaceAndTextureViews extends Activity { container.addView(mTextureView); final TransitionSet transition = new TransitionSet(); - transition.addTransition(new ChangeBounds()).addTransition(new Crossfade().addTargetId(0). - addTargetId(1).addTargetId(2)); + transition.addTransition(new ChangeBounds()).addTransition(new Crossfade().addTarget(0). + addTarget(1).addTarget(2)); toggleButton.setOnClickListener(new View.OnClickListener() { @Override diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 2a5b4da02678..c3bf9c1bd824 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -818,6 +818,10 @@ public class WifiManager { /** * End a requested batch scan for this applicaiton. Note that batched scan may * still occur if other apps are using them. + * + * @param requested {@link BatchedScanSettings} the scan settings you previously requested + * and now wish to stop. A value of null here will stop all scans requested by the + * calling App. * @hide */ public void stopBatchedScan(BatchedScanSettings requested) { diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 56261925c355..3deac1b6ea87 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -138,6 +138,7 @@ public class WifiNative { localLog(cmdId + "->" + mInterfacePrefix + command); boolean result = doBooleanCommandNative(mInterfacePrefix + command); localLog(cmdId + "<-" + result); + if (DBG) Log.d(mTAG, " returned " + result); return result; } } @@ -149,6 +150,7 @@ public class WifiNative { localLog(cmdId + "->" + mInterfacePrefix + command); int result = doIntCommandNative(mInterfacePrefix + command); localLog(cmdId + "<-" + result); + if (DBG) Log.d(mTAG, " returned " + result); return result; } } @@ -160,6 +162,7 @@ public class WifiNative { localLog(cmdId + "->" + mInterfacePrefix + command); String result = doStringCommandNative(mInterfacePrefix + command); localLog(cmdId + "<-" + result); + if (DBG) Log.d(mTAG, " returned " + result); return result; } } @@ -281,7 +284,7 @@ public class WifiNative { /** * Format of command - * DRIVER WLS_BATCHING SET SCAN_FRQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s + * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL=<z, w, t> RTT=s * where x is an ascii representation of an integer number of seconds between scans * r is an ascii representation of an integer number of scans per batch * y is an ascii representation of an integer number of the max AP to remember per scan @@ -295,7 +298,7 @@ public class WifiNative { */ public String setBatchedScanSettings(BatchedScanSettings settings) { if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP"); - String cmd = "DRIVER WLS_BATCHING SET SCAN_FRQ=" + settings.scanIntervalSec; + String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec; cmd += " MSCAN=" + settings.maxScansPerBatch; if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) { cmd += " BESTN=" + settings.maxApPerScan; diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 2bc22f26d859..0f1aa71e0d69 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -859,6 +859,7 @@ public class WifiStateMachine extends StateMachine { mExpectedBatchedScans = Integer.parseInt(scansExpected); setNextBatchedAlarm(mExpectedBatchedScans); } catch (NumberFormatException e) { + stopBatchedScan(); loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); } } @@ -876,6 +877,11 @@ public class WifiStateMachine extends StateMachine { } private void handleBatchedScanPollRequest() { + if (DBG) { + log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + + mBatchedScanMinPollTime + " , mBatchedScanSettings=" + + mBatchedScanSettings); + } // if there is no appropriate PollTime that's because we either aren't // batching or we've already set a time for a poll request if (mBatchedScanMinPollTime == 0) return; @@ -887,7 +893,7 @@ public class WifiStateMachine extends StateMachine { // do the poll and reset our timers startNextBatchedScan(); } else { - mAlarmManager.set(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, + mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, mBatchedScanIntervalIntent); mBatchedScanMinPollTime = 0; } @@ -932,7 +938,7 @@ public class WifiStateMachine extends StateMachine { // set the alarm to do the next poll. We set it a little short as we'd rather // wake up wearly than miss a scan due to buffer overflow - mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), mBatchedScanIntervalIntent); } @@ -964,11 +970,13 @@ public class WifiStateMachine extends StateMachine { * etc * "----" */ + private final static boolean DEBUG_PARSE = false; private void retrieveBatchedScanData() { String rawData = mWifiNative.getBatchedScanResults(); + if (DEBUG_PARSE) log("rawData = " + rawData); mBatchedScanMinPollTime = 0; - if (rawData == null) { - loge("Unexpected null BatchedScanResults"); + if (rawData == null || rawData.equalsIgnoreCase("OK")) { + loge("Unexpected BatchedScanResults :" + rawData); return; } @@ -978,17 +986,19 @@ public class WifiStateMachine extends StateMachine { final String TRUNCATED = "trunc"; final String AGE = "age="; final String DIST = "dist="; - final String DISTSD = "distsd="; + final String DISTSD = "distSd="; String splitData[] = rawData.split("\n"); int n = 0; if (splitData[n].startsWith(SCANCOUNT)) { try { scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); - } catch (NumberFormatException e) {} - } + } catch (NumberFormatException e) { + loge("scancount parseInt Exception from " + splitData[n]); + } + } else log("scancount not found"); if (scanCount == 0) { - loge("scanCount not found"); + loge("scanCount==0 - aborting"); return; } @@ -1010,13 +1020,15 @@ public class WifiStateMachine extends StateMachine { while (true) { while (n < splitData.length) { + if (DEBUG_PARSE) logd("parsing " + splitData[n]); if (splitData[n].equals(END_OF_BATCHES)) { - if (++n != splitData.length) { + if (n+1 != splitData.length) { loge("didn't consume " + (splitData.length-n)); } if (mBatchedScanResults.size() > 0) { - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } + logd("retrieveBatchedScanResults X"); return; } if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { @@ -1038,51 +1050,56 @@ public class WifiStateMachine extends StateMachine { logd("Found empty batch"); } } - n++; - } else if (splitData[n].equals(BSSID_STR)) { - bssid = splitData[n++].substring(BSSID_STR.length()); - } else if (splitData[n].equals(FREQ_STR)) { + } else if (splitData[n].equals(TRUNCATED)) { + batchedScanResult.truncated = true; + } else if (splitData[n].startsWith(BSSID_STR)) { + bssid = splitData[n].substring(BSSID_STR.length()); + } else if (splitData[n].startsWith(FREQ_STR)) { try { - freq = Integer.parseInt(splitData[n++].substring(FREQ_STR.length())); + freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); } catch (NumberFormatException e) { - loge("Invalid freqency: " + splitData[n-1]); + loge("Invalid freqency: " + splitData[n]); freq = 0; } - } else if (splitData[n].equals(AGE)) { + } else if (splitData[n].startsWith(AGE)) { try { - tsf = now - Long.parseLong(splitData[n++].substring(AGE.length())); + tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); } catch (NumberFormatException e) { - loge("Invalid timestamp: " + splitData[n-1]); + loge("Invalid timestamp: " + splitData[n]); tsf = 0; } - } else if (splitData[n].equals(SSID_STR)) { + } else if (splitData[n].startsWith(SSID_STR)) { wifiSsid = WifiSsid.createFromAsciiEncoded( - splitData[n++].substring(SSID_STR.length())); - } else if (splitData[n].equals(LEVEL_STR)) { + splitData[n].substring(SSID_STR.length())); + } else if (splitData[n].startsWith(LEVEL_STR)) { try { - level = Integer.parseInt(splitData[n++].substring(LEVEL_STR.length())); + level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); if (level > 0) level -= 256; } catch (NumberFormatException e) { - loge("Invalid level: " + splitData[n-1]); + loge("Invalid level: " + splitData[n]); level = 0; } - } else if (splitData[n].equals(DIST)) { + } else if (splitData[n].startsWith(DIST)) { try { - dist = Integer.parseInt(splitData[n++].substring(DIST.length())); + dist = Integer.parseInt(splitData[n].substring(DIST.length())); } catch (NumberFormatException e) { - loge("Invalid distance: " + splitData[n-1]); + loge("Invalid distance: " + splitData[n]); dist = ScanResult.UNSPECIFIED; } - } else if (splitData[n].equals(DISTSD)) { + } else if (splitData[n].startsWith(DISTSD)) { try { - distSd = Integer.parseInt(splitData[n++].substring(DISTSD.length())); + distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); } catch (NumberFormatException e) { - loge("Invalid distanceSd: " + splitData[n-1]); + loge("Invalid distanceSd: " + splitData[n]); distSd = ScanResult.UNSPECIFIED; } + } else { + loge("Unable to parse batched scan result line: " + splitData[n]); } + n++; } rawData = mWifiNative.getBatchedScanResults(); + if (DEBUG_PARSE) log("reading more data:\n" + rawData); if (rawData == null) { loge("Unexpected null BatchedScanResults"); return; @@ -2392,6 +2409,7 @@ public class WifiStateMachine extends StateMachine { break; case CMD_POLL_BATCHED_SCAN: handleBatchedScanPollRequest(); + break; case CMD_START_NEXT_BATCHED_SCAN: startNextBatchedScan(); break; |