Merge "Define config_volte_replacement_rat." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 91fcab1..529ffe2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2725,8 +2725,6 @@
method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void closeContextMenu();
method public void closeOptionsMenu();
- method public void convertFromTranslucent();
- method public void convertToTranslucent(android.app.Activity.TranslucentConversionListener);
method public android.app.PendingIntent createPendingResult(int, android.content.Intent, int);
method public final deprecated void dismissDialog(int);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
@@ -2912,10 +2910,6 @@
field public static final int RESULT_OK = -1; // 0xffffffff
}
- public static abstract interface Activity.TranslucentConversionListener {
- method public abstract void onTranslucentConversionComplete(boolean);
- }
-
public deprecated class ActivityGroup extends android.app.Activity {
ctor public ActivityGroup();
ctor public ActivityGroup(boolean);
@@ -10965,6 +10959,7 @@
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 +10967,8 @@
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 +11074,7 @@
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 +25514,18 @@
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 +25535,8 @@
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);
@@ -30157,6 +30161,7 @@
method public void clearSslPreferences();
method public deprecated void clearView();
method public android.webkit.WebBackForwardList copyBackForwardList();
+ method public android.print.PrintDocumentAdapter createPrintDocumentAdapter();
method public void destroy();
method public void documentHasImages(android.os.Message);
method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 57686a4..a38fbbf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4907,6 +4907,8 @@
*
* @see #convertToTranslucent(TranslucentConversionListener)
* @see TranslucentConversionListener
+ *
+ * @hide
*/
public void convertFromTranslucent() {
try {
@@ -4937,6 +4939,8 @@
*
* @see #convertFromTranslucent()
* @see TranslucentConversionListener
+ *
+ * @hide
*/
public void convertToTranslucent(TranslucentConversionListener callback) {
try {
@@ -5441,6 +5445,8 @@
* opaque using {@link Activity#convertFromTranslucent()} and before it has been drawn
* translucent again following a call to {@link
* Activity#convertToTranslucent(TranslucentConversionListener)}.
+ *
+ * @hide
*/
public interface TranslucentConversionListener {
/**
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 18fffc0..ec23f08 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -874,6 +874,20 @@
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 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 c3a636d..4608ab9 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -957,6 +957,22 @@
/**
* <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 f83dad7..3fcd2f9 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -587,6 +587,7 @@
* 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/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index b1e427e..a1ffa8c 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -226,6 +226,12 @@
StringBuilder builder = new StringBuilder();
builder.append("PrintAttributes{");
builder.append("mediaSize: ").append(mMediaSize);
+ if (mMediaSize != null) {
+ builder.append(", orientation: ").append(mMediaSize.isPortrait()
+ ? "portrait" : "landscape");
+ } else {
+ builder.append(", orientation: ").append("null");
+ }
builder.append(", resolution: ").append(mResolution);
builder.append(", margins: ").append(mMargins);
builder.append(", colorMode: ").append(colorModeToString(mColorMode));
@@ -880,12 +886,6 @@
* @param bottomMils The bottom margin in mils (thousands of an inch).
*/
public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
- if (leftMils > rightMils) {
- throw new IllegalArgumentException("leftMils cannot be less than rightMils.");
- }
- if (topMils > bottomMils) {
- throw new IllegalArgumentException("topMils cannot be less than bottomMils.");
- }
mTopMils = topMils;
mLeftMils = leftMils;
mRightMils = rightMils;
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index c81ca95..8ac34c1 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -20,8 +20,6 @@
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
-import java.util.List;
-
/**
* Base class that provides the content of a document to be printed.
*
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index de28bd3..42bea6d 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -16,7 +16,6 @@
package android.print;
-
/**
* This class represents a print job from the perspective of
* an application.
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 0ffc40a..012e76ab 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -20,7 +20,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java
index eacd40d..b1c07f5 100644
--- a/core/java/android/text/AndroidBidi.java
+++ b/core/java/android/text/AndroidBidi.java
@@ -60,6 +60,9 @@
*/
public static Directions directions(int dir, byte[] levels, int lstart,
char[] chars, int cstart, int len) {
+ if (len == 0) {
+ return Layout.DIRS_ALL_LEFT_TO_RIGHT;
+ }
int baseLevel = dir == Layout.DIR_LEFT_TO_RIGHT ? 0 : 1;
int curLevel = levels[lstart];
diff --git a/core/java/android/transition/TextChange.java b/core/java/android/transition/TextChange.java
index 4f14d46..0b1e4e1 100644
--- a/core/java/android/transition/TextChange.java
+++ b/core/java/android/transition/TextChange.java
@@ -137,14 +137,17 @@
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
- if (startValues == null || endValues == null || !(endValues.view instanceof TextView)) {
+ if (startValues == null || endValues == null ||
+ !(startValues.view instanceof TextView) || !(endValues.view instanceof TextView)) {
return null;
}
final TextView view = (TextView) endValues.view;
Map<String, Object> startVals = startValues.values;
Map<String, Object> endVals = endValues.values;
- final CharSequence startText = (CharSequence) startVals.get(PROPNAME_TEXT);
- final CharSequence endText = (CharSequence) endVals.get(PROPNAME_TEXT);
+ final CharSequence startText = startVals.get(PROPNAME_TEXT) != null ?
+ (CharSequence) startVals.get(PROPNAME_TEXT) : "";
+ final CharSequence endText = endVals.get(PROPNAME_TEXT) != null ?
+ (CharSequence) endVals.get(PROPNAME_TEXT) : "";
if (!startText.equals(endText)) {
view.setText(startText);
Animator anim;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 8ea9d48..c588c6b 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -29,6 +29,7 @@
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 @@
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 @@
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 @@
* 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 @@
* @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 @@
* 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 @@
}
/**
+ * 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 @@
* 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 @@
// 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 @@
mStartValues.idValues.put((int) id, values);
}
} else {
- mStartValues.itemIdValues.put(id, values);
+ mStartValues.itemIdValues.put(itemId, values);
}
} else {
if (!isListViewItem) {
@@ -870,10 +1111,25 @@
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 @@
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 ebedeeb..eeb6cba 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -235,7 +235,7 @@
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 1972c2a..f72b36e 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -155,8 +155,8 @@
}
@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 @@
}
@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 @@
@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 @@
@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/android/view/View.java b/core/java/android/view/View.java
index 30531ed..8f8f9c6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8008,7 +8008,7 @@
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean result = false;
- if (KeyEvent.isConfirmKey(event.getKeyCode())) {
+ if (KeyEvent.isConfirmKey(keyCode)) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
@@ -8050,28 +8050,21 @@
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
- boolean result = false;
+ if (KeyEvent.isConfirmKey(keyCode)) {
+ if ((mViewFlags & ENABLED_MASK) == DISABLED) {
+ return true;
+ }
+ if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
+ setPressed(false);
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER: {
- if ((mViewFlags & ENABLED_MASK) == DISABLED) {
- return true;
+ if (!mHasPerformedLongPress) {
+ // This is a tap, so remove the longpress check
+ removeLongPressCallback();
+ return performClick();
}
- if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {
- setPressed(false);
-
- if (!mHasPerformedLongPress) {
- // This is a tap, so remove the longpress check
- removeLongPressCallback();
-
- result = performClick();
- }
- }
- break;
}
}
- return result;
+ return false;
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8fc3ce3..15331dc 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -31,9 +31,8 @@
import android.os.CancellationSignal;
import android.os.Looper;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
import android.os.StrictMode;
-import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
@@ -1069,41 +1068,21 @@
}
/**
- * Exports the contents of this Webview as PDF. Only supported for API levels
+ * Creates a PrintDocumentAdapter that provides the content of this Webview for printing.
+ * Only supported for API levels
* {@link android.os.Build.VERSION_CODES#KITKAT} and above.
*
- * TODO(sgurun) the parameter list is stale. Fix it before unhiding.
- *
- * @param fd The FileDescriptor to export the PDF contents to. Cannot be null.
- * @param width The page width. Should be larger than 0.
- * @param height The page height. Should be larger than 0.
- * @param resultCallback A callback to be invoked when the PDF content is exported.
- * A true indicates success, and a false failure. Cannot be null.
- * @param cancellationSignal Signal for cancelling the PDF conversion request. Must not
- * be null.
- *
- * The PDF conversion is done asynchronously and the PDF output is written to the provided
- * file descriptor. The caller should not close the file descriptor until the resultCallback
- * is called, indicating PDF conversion is complete. Webview will never close the file
- * descriptor.
- * Limitations: Webview cannot be drawn during the PDF export so the application is
- * recommended to take it offscreen, or putting in a layer with an overlaid progress
- * UI / spinner.
- *
- * If the caller cancels the task using the cancellationSignal, the cancellation will be
- * acked using the resultCallback signal.
- *
- * Throws an exception if an IO error occurs accessing the file descriptor.
- *
- * TODO(sgurun) margins, explain the units, make it public.
- * @hide
+ * The adapter works by converting the Webview contents to a PDF stream. The Webview cannot
+ * be drawn during the conversion process - any such draws are undefined. It is recommended
+ * to use a dedicated off screen Webview for the printing. If necessary, an application may
+ * temporarily hide a visible WebView by using a custom PrintDocumentAdapter instance
+ * wrapped around the object returned and observing the onStart and onFinish methods. See
+ * {@link android.print.PrintDocumentAdapter} for more information.
*/
- public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
- throws java.io.IOException {
+ public PrintDocumentAdapter createPrintDocumentAdapter() {
checkThread();
- if (DebugFlags.TRACE_API) Log.d(LOGTAG, "exportToPdf");
- mProvider.exportToPdf(fd, attributes, resultCallback, cancellationSignal);
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "createPrintDocumentAdapter");
+ return mProvider.createPrintDocumentAdapter();
}
/**
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 3f22d53..e82ce30 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -62,7 +62,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
-import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
import android.security.KeyChain;
import android.text.Editable;
import android.text.InputType;
@@ -2894,12 +2894,10 @@
}
/**
- * See {@link WebView#exportToPdf()}
+ * See {@link WebView#createPrintDocumentAdapter()}
*/
@Override
- public void exportToPdf(android.os.ParcelFileDescriptor fd, PrintAttributes attributes,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
- throws java.io.IOException {
+ public PrintDocumentAdapter createPrintDocumentAdapter() {
// K-only API not implemented in WebViewClassic.
throw new IllegalStateException("This API not supported on Android 4.3 and earlier");
}
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index d625d8a..696aad4 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -25,10 +25,8 @@
import android.graphics.drawable.Drawable;
import android.net.http.SslCertificate;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -149,9 +147,7 @@
public Picture capturePicture();
- public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
- throws java.io.IOException;
+ public PrintDocumentAdapter createPrintDocumentAdapter();
public float getScale();
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 68c3d0a..0c2e721 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 @@
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 ca7f5d0..f3891c7 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -201,6 +201,13 @@
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
deleted file mode 100644
index da9fa91..0000000
--- a/core/res/res/drawable-xhdpi/default_wallpaper.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7ddf2e9..4a26a05 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/core/res/res/values/config.xml b/core/res/res/values/config.xml
index baaa7c6..d4b834a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -450,6 +450,13 @@
The default is false. -->
<bool name="config_lidControlsSleep">false</bool>
+ <!-- Indicate whether to allow the device to suspend when the screen is off
+ due to the proximity sensor. This resource should only be set to true
+ if the sensor HAL correctly handles the proximity sensor as a wake-up source.
+ Otherwise, the device may fail to wake out of suspend reliably.
+ The default is false. -->
+ <bool name="config_suspendWhenScreenOffDueToProximity">false</bool>
+
<!-- Control the behavior when the user long presses the power button.
0 - Nothing
1 - Global actions menu
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4ac49c9..44891a8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -260,6 +260,7 @@
<java-symbol type="bool" name="config_sip_wifi_only" />
<java-symbol type="bool" name="config_sms_capable" />
<java-symbol type="bool" name="config_sms_utf8_support" />
+ <java-symbol type="bool" name="config_suspendWhenScreenOffDueToProximity" />
<java-symbol type="bool" name="config_swipeDisambiguation" />
<java-symbol type="bool" name="config_syncstorageengine_masterSyncAutomatically" />
<java-symbol type="bool" name="config_telephony_use_own_number_for_voicemail" />
diff --git a/docs/downloads/training/LocationProvider.zip b/docs/downloads/training/LocationProvider.zip
new file mode 100644
index 0000000..d5ee311
--- /dev/null
+++ b/docs/downloads/training/LocationProvider.zip
Binary files differ
diff --git a/docs/html/training/location/activity-recognition.jd b/docs/html/training/location/activity-recognition.jd
index 47ba5f8..d50064b 100644
--- a/docs/html/training/location/activity-recognition.jd
+++ b/docs/html/training/location/activity-recognition.jd
@@ -31,13 +31,13 @@
</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 5ebbb84..e03eac6 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -85,4 +85,12 @@
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 0000000..e36bac1
--- /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 ebf553cc..0c4f9df 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -631,6 +631,10 @@
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/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 7ce15c5..fd9257a 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -66,23 +66,23 @@
virtual ~DrawBatch() { mOps.clear(); }
- virtual void add(DrawOp* op, bool opaqueOverBounds) {
+ virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) {
// NOTE: ignore empty bounds special case, since we don't merge across those ops
- mBounds.unionWith(op->state.mBounds);
+ mBounds.unionWith(state->mBounds);
mAllOpsOpaque &= opaqueOverBounds;
- mOps.add(op);
+ mOps.add(OpStatePair(op, state));
}
- bool intersects(Rect& rect) {
+ bool intersects(const Rect& rect) {
if (!rect.intersects(mBounds)) return false;
for (unsigned int i = 0; i < mOps.size(); i++) {
- if (rect.intersects(mOps[i]->state.mBounds)) {
+ if (rect.intersects(mOps[i].state->mBounds)) {
#if DEBUG_DEFER
- DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i],
- mOps[i]->state.mBounds.left, mOps[i]->state.mBounds.top,
- mOps[i]->state.mBounds.right, mOps[i]->state.mBounds.bottom);
- mOps[i]->output(2);
+ DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i].op,
+ mOps[i].state->mBounds.left, mOps[i].state->mBounds.top,
+ mOps[i].state->mBounds.right, mOps[i].state->mBounds.bottom);
+ mOps[i].op->output(2);
#endif
return true;
}
@@ -97,9 +97,9 @@
status_t status = DrawGlInfo::kStatusDone;
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
for (unsigned int i = 0; i < mOps.size(); i++) {
- DrawOp* op = mOps[i];
-
- renderer.restoreDisplayState(op->state);
+ DrawOp* op = mOps[i].op;
+ const DeferredDisplayState* state = mOps[i].state;
+ renderer.restoreDisplayState(*state);
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
renderer.eventMark(op->name());
@@ -108,7 +108,7 @@
status |= op->applyDraw(renderer, dirty);
#if DEBUG_MERGE_BEHAVIOR
- Rect& bounds = mOps[i]->state.mBounds;
+ const Rect& bounds = state->mBounds;
int batchColor = 0x1f000000;
if (getBatchId() & 0x1) batchColor |= 0x0000ff;
if (getBatchId() & 0x2) batchColor |= 0x00ff00;
@@ -127,7 +127,7 @@
Region uncovered(android::Rect(bounds.left, bounds.top, bounds.right, bounds.bottom));
for (unsigned int i = 0; i < mOps.size(); i++) {
- Rect &r = mOps[i]->state.mBounds;
+ const Rect &r = mOps[i].state->mBounds;
uncovered.subtractSelf(android::Rect(r.left, r.top, r.right, r.bottom));
}
return uncovered.isEmpty();
@@ -138,7 +138,7 @@
inline int count() const { return mOps.size(); }
protected:
- Vector<DrawOp*> mOps;
+ Vector<OpStatePair> mOps;
Rect mBounds; // union of bounds of contained ops
private:
bool mAllOpsOpaque;
@@ -184,19 +184,19 @@
* False positives can lead to information from the paints of subsequent merged operations being
* dropped, so we make simplifying qualifications on the ops that can merge, per op type.
*/
- bool canMergeWith(DrawOp* op) {
+ bool canMergeWith(const DrawOp* op, const DeferredDisplayState* state) {
bool isTextBatch = getBatchId() == DeferredDisplayList::kOpBatch_Text ||
getBatchId() == DeferredDisplayList::kOpBatch_ColorText;
// Overlapping other operations is only allowed for text without shadow. For other ops,
// multiDraw isn't guaranteed to overdraw correctly
- if (!isTextBatch || op->state.mDrawModifiers.mHasShadow) {
- if (intersects(op->state.mBounds)) return false;
+ if (!isTextBatch || state->mDrawModifiers.mHasShadow) {
+ if (intersects(state->mBounds)) return false;
}
- const DeferredDisplayState& lhs = op->state;
- const DeferredDisplayState& rhs = mOps[0]->state;
+ const DeferredDisplayState* lhs = state;
+ const DeferredDisplayState* rhs = mOps[0].state;
- if (NEQ_FALPHA(lhs.mAlpha, rhs.mAlpha)) return false;
+ if (NEQ_FALPHA(lhs->mAlpha, rhs->mAlpha)) return false;
/* Clipping compatibility check
*
@@ -204,9 +204,9 @@
* clip for that side.
*/
const int currentFlags = mClipSideFlags;
- const int newFlags = op->state.mClipSideFlags;
+ const int newFlags = state->mClipSideFlags;
if (currentFlags != kClipSide_None || newFlags != kClipSide_None) {
- const Rect& opBounds = op->state.mBounds;
+ const Rect& opBounds = state->mBounds;
float boundsDelta = mBounds.left - opBounds.left;
if (!checkSide(currentFlags, newFlags, kClipSide_Left, boundsDelta)) return false;
boundsDelta = mBounds.top - opBounds.top;
@@ -220,9 +220,9 @@
}
// if paints are equal, then modifiers + paint attribs don't need to be compared
- if (op->mPaint == mOps[0]->mPaint) return true;
+ if (op->mPaint == mOps[0].op->mPaint) return true;
- if (op->getPaintAlpha() != mOps[0]->getPaintAlpha()) return false;
+ if (op->getPaintAlpha() != mOps[0].op->getPaintAlpha()) return false;
/* Draw Modifiers compatibility check
*
@@ -236,8 +236,8 @@
*
* These ignore cases prevent us from simply memcmp'ing the drawModifiers
*/
- const DrawModifiers& lhsMod = lhs.mDrawModifiers;
- const DrawModifiers& rhsMod = rhs.mDrawModifiers;
+ const DrawModifiers& lhsMod = lhs->mDrawModifiers;
+ const DrawModifiers& rhsMod = rhs->mDrawModifiers;
if (lhsMod.mShader != rhsMod.mShader) return false;
if (lhsMod.mColorFilter != rhsMod.mColorFilter) return false;
@@ -249,15 +249,15 @@
return true;
}
- virtual void add(DrawOp* op, bool opaqueOverBounds) {
- DrawBatch::add(op, opaqueOverBounds);
+ virtual void add(DrawOp* op, DeferredDisplayState* state, bool opaqueOverBounds) {
+ DrawBatch::add(op, state, opaqueOverBounds);
- const int newClipSideFlags = op->state.mClipSideFlags;
+ const int newClipSideFlags = state->mClipSideFlags;
mClipSideFlags |= newClipSideFlags;
- if (newClipSideFlags & kClipSide_Left) mClipRect.left = op->state.mClip.left;
- if (newClipSideFlags & kClipSide_Top) mClipRect.top = op->state.mClip.top;
- if (newClipSideFlags & kClipSide_Right) mClipRect.right = op->state.mClip.right;
- if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = op->state.mClip.bottom;
+ if (newClipSideFlags & kClipSide_Left) mClipRect.left = state->mClip.left;
+ if (newClipSideFlags & kClipSide_Top) mClipRect.top = state->mClip.top;
+ if (newClipSideFlags & kClipSide_Right) mClipRect.right = state->mClip.right;
+ if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = state->mClip.bottom;
}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
@@ -271,7 +271,7 @@
// clipping in the merged case is done ahead of time since all ops share the clip (if any)
renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : NULL);
- DrawOp* op = mOps[0];
+ DrawOp* op = mOps[0].op;
DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
buffer.writeCommand(0, "multiDraw");
buffer.writeCommand(1, op->name());
@@ -297,11 +297,11 @@
class StateOpBatch : public Batch {
public:
// creates a single operation batch
- StateOpBatch(StateOp* op) : mOp(op) {}
+ StateOpBatch(const StateOp* op, const DeferredDisplayState* state) : mOp(op), mState(state) {}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
DEFER_LOGD("replaying state op batch %p", this);
- renderer.restoreDisplayState(mOp->state);
+ renderer.restoreDisplayState(*mState);
// use invalid save count because it won't be used at flush time - RestoreToCountOp is the
// only one to use it, and we don't use that class at flush time, instead calling
@@ -313,16 +313,18 @@
private:
const StateOp* mOp;
+ const DeferredDisplayState* mState;
};
class RestoreToCountBatch : public Batch {
public:
- RestoreToCountBatch(StateOp* op, int restoreCount) : mOp(op), mRestoreCount(restoreCount) {}
+ RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state, int restoreCount) :
+ mOp(op), mState(state), mRestoreCount(restoreCount) {}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
- renderer.restoreDisplayState(mOp->state);
+ renderer.restoreDisplayState(*mState);
renderer.restoreToCount(mRestoreCount);
return DrawGlInfo::kStatusDone;
}
@@ -330,6 +332,8 @@
private:
// we use the state storage for the RestoreToCountOp, but don't replay the op itself
const StateOp* mOp;
+ const DeferredDisplayState* mState;
+
/*
* The count used here represents the flush() time saveCount. This is as opposed to the
* DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and
@@ -480,12 +484,27 @@
}
void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
- if (renderer.storeDisplayState(op->state, getDrawOpDeferFlags())) {
+ /* 1: op calculates local bounds */
+ DeferredDisplayState* const state = createState();
+ if (op->getLocalBounds(renderer.getDrawModifiers(), state->mBounds)) {
+ if (state->mBounds.isEmpty()) {
+ // valid empty bounds, don't bother deferring
+ tryRecycleState(state);
+ return;
+ }
+ } else {
+ state->mBounds.setEmpty();
+ }
+
+ /* 2: renderer calculates global bounds + stores state */
+ if (renderer.storeDisplayState(*state, getDrawOpDeferFlags())) {
+ tryRecycleState(state);
return; // quick rejected
}
+ /* 3: ask op for defer info, given renderer state */
DeferInfo deferInfo;
- op->onDefer(renderer, deferInfo);
+ op->onDefer(renderer, deferInfo, *state);
// complex clip has a complex set of expectations on the renderer state - for now, avoid taking
// the merge path in those cases
@@ -493,8 +512,8 @@
deferInfo.opaqueOverBounds &= !recordingComplexClip() && mSaveStack.isEmpty();
if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() &&
- op->state.mClipSideFlags != kClipSide_ConservativeFull &&
- deferInfo.opaqueOverBounds && op->state.mBounds.contains(mBounds)) {
+ state->mClipSideFlags != kClipSide_ConservativeFull &&
+ deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) {
// avoid overdraw by resetting drawing state + discarding drawing ops
discardDrawingBatches(mBatches.size() - 1);
resetBatchingState();
@@ -503,7 +522,7 @@
if (CC_UNLIKELY(renderer.getCaches().drawReorderDisabled)) {
// TODO: elegant way to reuse batches?
DrawBatch* b = new DrawBatch(deferInfo);
- b->add(op, deferInfo.opaqueOverBounds);
+ b->add(op, state, deferInfo.opaqueOverBounds);
mBatches.add(b);
return;
}
@@ -515,10 +534,10 @@
// (eventually, should be similar shader)
int insertBatchIndex = mBatches.size();
if (!mBatches.isEmpty()) {
- if (op->state.mBounds.isEmpty()) {
+ if (state->mBounds.isEmpty()) {
// don't know the bounds for op, so add to last batch and start from scratch on next op
DrawBatch* b = new DrawBatch(deferInfo);
- b->add(op, deferInfo.opaqueOverBounds);
+ b->add(op, state, deferInfo.opaqueOverBounds);
mBatches.add(b);
resetBatchingState();
#if DEBUG_DEFER
@@ -531,7 +550,7 @@
if (deferInfo.mergeable) {
// Try to merge with any existing batch with same mergeId.
if (mMergingBatches[deferInfo.batchId].get(deferInfo.mergeId, targetBatch)) {
- if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op)) {
+ if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) {
targetBatch = NULL;
}
}
@@ -554,14 +573,14 @@
if (!targetBatch) break; // found insert position, quit
}
- if (overBatch->intersects(op->state.mBounds)) {
+ if (overBatch->intersects(state->mBounds)) {
// NOTE: it may be possible to optimize for special cases where two operations
// of the same batch/paint could swap order, such as with a non-mergeable
// (clipped) and a mergeable text operation
targetBatch = NULL;
#if DEBUG_DEFER
- DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
- targetIndex, i);
+ DEFER_LOGD("op couldn't join batch %p, was intersected by batch %d",
+ targetBatch, i);
op->output(2);
#endif
break;
@@ -586,14 +605,15 @@
mBatches.insertAt(targetBatch, insertBatchIndex);
}
- targetBatch->add(op, deferInfo.opaqueOverBounds);
+ targetBatch->add(op, state, deferInfo.opaqueOverBounds);
}
void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op) {
DEFER_LOGD("%p adding state op barrier at pos %d", this, mBatches.size());
- renderer.storeDisplayState(op->state, getStateOpDeferFlags());
- mBatches.add(new StateOpBatch(op));
+ DeferredDisplayState* state = createState();
+ renderer.storeDisplayState(*state, getStateOpDeferFlags());
+ mBatches.add(new StateOpBatch(op, state));
resetBatchingState();
}
@@ -604,8 +624,9 @@
// store displayState for the restore operation, as it may be associated with a saveLayer that
// doesn't have kClip_SaveFlag set
- renderer.storeDisplayState(op->state, getStateOpDeferFlags());
- mBatches.add(new RestoreToCountBatch(op, newSaveCount));
+ DeferredDisplayState* state = createState();
+ renderer.storeDisplayState(*state, getStateOpDeferFlags());
+ mBatches.add(new RestoreToCountBatch(op, state, newSaveCount));
resetBatchingState();
}
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 1ef0152..3dcbd0b 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -18,11 +18,13 @@
#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
#include <utils/Errors.h>
+#include <utils/LinearAllocator.h>
#include <utils/Vector.h>
+#include <utils/TinyHashMap.h>
#include "Matrix.h"
+#include "OpenGLRenderer.h"
#include "Rect.h"
-#include "utils/TinyHashMap.h"
class SkBitmap;
@@ -34,6 +36,8 @@
class SaveOp;
class SaveLayerOp;
class StateOp;
+
+class DeferredDisplayState;
class OpenGLRenderer;
class Batch;
@@ -42,6 +46,38 @@
typedef const void* mergeid_t;
+class DeferredDisplayState {
+public:
+ /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+ static void* operator new(size_t size, LinearAllocator& allocator) {
+ return allocator.alloc(size);
+ }
+
+ // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
+ Rect mBounds;
+
+ // the below are set and used by the OpenGLRenderer at record and deferred playback
+ bool mClipValid;
+ Rect mClip;
+ int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
+ bool mClipped;
+ mat4 mMatrix;
+ DrawModifiers mDrawModifiers;
+ float mAlpha;
+};
+
+class OpStatePair {
+public:
+ OpStatePair()
+ : op(NULL), state(NULL) {}
+ OpStatePair(DrawOp* newOp, const DeferredDisplayState* newState)
+ : op(newOp), state(newState) {}
+ OpStatePair(const OpStatePair& other)
+ : op(other.op), state(other.state) {}
+ DrawOp* op;
+ const DeferredDisplayState* state;
+};
+
class DeferredDisplayList {
public:
DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
@@ -84,6 +120,14 @@
void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
private:
+ DeferredDisplayState* createState() {
+ return new (mAllocator) DeferredDisplayState();
+ }
+
+ void tryRecycleState(DeferredDisplayState* state) {
+ mAllocator.rewindIfLastAlloc(state, sizeof(DeferredDisplayState));
+ }
+
/**
* Resets the batching back-pointers, creating a barrier in the operation stream so that no ops
* added in the future will be inserted into a batch that already exist.
@@ -131,6 +175,8 @@
* collide, which avoids the need to resolve mergeid collisions.
*/
TinyHashMap<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count];
+
+ LinearAllocator mAllocator;
};
/**
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 194be9e..1cd5f1c 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -26,6 +26,7 @@
#include <private/hwui/DrawGlInfo.h>
+#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
@@ -35,8 +36,6 @@
#include <androidfw/ResourceTypes.h>
-#include "utils/LinearAllocator.h"
-
#include "Debug.h"
#define TRANSLATION 0x0001
@@ -114,7 +113,6 @@
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
-
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 42e11d0..a17942e 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -82,15 +82,6 @@
// NOTE: it would be nice to declare constants and overriding the implementation in each op to
// point at the constants, but that seems to require a .cpp file
virtual const char* name() = 0;
-
- /**
- * Stores the relevant canvas state of the object between deferral and replay (if the canvas
- * state supports being stored) See OpenGLRenderer::simpleClipAndState()
- *
- * TODO: don't reserve space for StateOps that won't be deferred
- */
- DeferredDisplayState state;
-
};
class StateOp : public DisplayListOp {
@@ -129,14 +120,6 @@
return;
}
- if (getLocalBounds(state.mBounds)) {
- // valid empty bounds, don't bother deferring
- if (state.mBounds.isEmpty()) return;
- } else {
- // empty bounds signify bounds can't be calculated
- state.mBounds.setEmpty();
- }
-
deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
}
@@ -159,11 +142,11 @@
* reducing which operations are tagged as mergeable.
*/
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
status_t status = DrawGlInfo::kStatusDone;
for (unsigned int i = 0; i < ops.size(); i++) {
- renderer.restoreDisplayState(ops[i]->state, true);
- status |= ops[i]->applyDraw(renderer, dirty);
+ renderer.restoreDisplayState(*(ops[i].state), true);
+ status |= ops[i].op->applyDraw(renderer, dirty);
}
return status;
}
@@ -178,20 +161,23 @@
*
* if a subclass can set deferInfo.mergeable to true, it should implement multiDraw()
*/
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {}
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {}
/**
* Query the conservative, local bounds (unmapped) bounds of the op.
*
* returns true if bounds exist
*/
- virtual bool getLocalBounds(Rect& localBounds) { return false; }
+ virtual bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
+ return false;
+ }
// TODO: better refine localbounds usage
void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
bool getQuickRejected() { return mQuickRejected; }
- inline int getPaintAlpha() {
+ inline int getPaintAlpha() const {
return OpenGLRenderer::getAlphaDirect(mPaint);
}
@@ -208,7 +194,7 @@
// Helper method for determining op opaqueness. Assumes op fills its bounds in local
// coordinates, and that paint's alpha is used
- inline bool isOpaqueOverBounds() {
+ inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
// ensure that local bounds cover mapped bounds
if (!state.mMatrix.isSimple()) return false;
@@ -251,12 +237,13 @@
// default empty constructor for bounds, to be overridden in child constructor body
DrawBoundedOp(SkPaint* paint): DrawOp(paint) { }
- bool getLocalBounds(Rect& localBounds) {
+ bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
localBounds.set(mLocalBounds);
- if (state.mDrawModifiers.mHasShadow) {
+ if (drawModifiers.mHasShadow) {
+ // TODO: inspect paint's looper directly
Rect shadow(mLocalBounds);
- shadow.translate(state.mDrawModifiers.mShadowDx, state.mDrawModifiers.mShadowDy);
- shadow.outset(state.mDrawModifiers.mShadowRadius);
+ shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy);
+ shadow.outset(drawModifiers.mShadowRadius);
localBounds.unionWith(shadow);
}
return true;
@@ -777,8 +764,10 @@
* the current layer, if any.
*/
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
- renderer.restoreDisplayState(state, true); // restore all but the clip
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
+ const DeferredDisplayState& firstState = *(ops[0].state);
+ renderer.restoreDisplayState(firstState, true); // restore all but the clip
+
TextureVertex vertices[6 * ops.size()];
TextureVertex* vertex = &vertices[0];
@@ -788,14 +777,15 @@
// TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
// and allowing them to be merged in getBatchId()
for (unsigned int i = 0; i < ops.size(); i++) {
- const Rect& opBounds = ops[i]->state.mBounds;
+ const DeferredDisplayState& state = *(ops[i].state);
+ const Rect& opBounds = state.mBounds;
// When we reach multiDraw(), the matrix can be either
// pureTranslate or simple (translate and/or scale).
// If the matrix is not pureTranslate, then we have a scale
- if (!ops[i]->state.mMatrix.isPureTranslate()) transformed = true;
+ if (state.mMatrix.isPureTranslate()) transformed = true;
Rect texCoords(0, 0, 1, 1);
- ((DrawBitmapOp*) ops[i])->mUvMapper.map(texCoords);
+ ((DrawBitmapOp*) ops[i].op)->mUvMapper.map(texCoords);
SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
@@ -806,8 +796,7 @@
SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
if (hasLayer) {
- const Rect& dirty = ops[i]->state.mBounds;
- renderer.dirtyLayer(dirty.left, dirty.top, dirty.right, dirty.bottom);
+ renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom);
}
}
@@ -821,7 +810,8 @@
virtual const char* name() { return "DrawBitmap"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
@@ -861,7 +851,8 @@
virtual const char* name() { return "DrawBitmapMatrix"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -890,7 +881,8 @@
virtual const char* name() { return "DrawBitmapRect"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -915,7 +907,8 @@
virtual const char* name() { return "DrawBitmapData"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
};
@@ -939,7 +932,8 @@
virtual const char* name() { return "DrawBitmapMesh"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -989,15 +983,16 @@
* is also responsible for dirtying the current layer, if any.
*/
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
- renderer.restoreDisplayState(state, true);
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
+ const DeferredDisplayState& firstState = *(ops[0].state);
+ renderer.restoreDisplayState(firstState, true); // restore all but the clip
// Batches will usually contain a small number of items so it's
// worth performing a first iteration to count the exact number
// of vertices we need in the new mesh
uint32_t totalVertices = 0;
for (unsigned int i = 0; i < ops.size(); i++) {
- totalVertices += ((DrawPatchOp*) ops[i])->getMesh(renderer)->verticesCount;
+ totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount;
}
const bool hasLayer = renderer.hasLayer();
@@ -1012,7 +1007,8 @@
// enforces ops drawn by this function to have a pure translate or
// identity matrix
for (unsigned int i = 0; i < ops.size(); i++) {
- DrawPatchOp* patchOp = (DrawPatchOp*) ops[i];
+ DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op;
+ const DeferredDisplayState* state = ops[i].state;
const Patch* opMesh = patchOp->getMesh(renderer);
uint32_t vertexCount = opMesh->verticesCount;
if (vertexCount == 0) continue;
@@ -1020,9 +1016,9 @@
// We use the bounds to know where to translate our vertices
// Using patchOp->state.mBounds wouldn't work because these
// bounds are clipped
- const float tx = (int) floorf(patchOp->state.mMatrix.getTranslateX() +
+ const float tx = (int) floorf(state->mMatrix.getTranslateX() +
patchOp->mLocalBounds.left + 0.5f);
- const float ty = (int) floorf(patchOp->state.mMatrix.getTranslateY() +
+ const float ty = (int) floorf(state->mMatrix.getTranslateY() +
patchOp->mLocalBounds.top + 0.5f);
// Copy & transform all the vertices for the current operation
@@ -1074,12 +1070,13 @@
virtual const char* name() { return "DrawPatch"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
- deferInfo.opaqueOverBounds = isOpaqueOverBounds() && mBitmap->isOpaque();
+ deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
}
private:
@@ -1119,7 +1116,7 @@
DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
: DrawBoundedOp(left, top, right, bottom, paint) {};
- bool getLocalBounds(Rect& localBounds) {
+ bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
localBounds.set(mLocalBounds);
if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
localBounds.outset(strokeWidthOutset());
@@ -1127,7 +1124,8 @@
return true;
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
if (mPaint->getPathEffect()) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
} else {
@@ -1152,9 +1150,10 @@
OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
- DrawStrokableOp::onDefer(renderer, deferInfo);
- deferInfo.opaqueOverBounds = isOpaqueOverBounds() &&
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
+ DrawStrokableOp::onDefer(renderer, deferInfo, state);
+ deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
mPaint->getStyle() == SkPaint::kFill_Style;
}
@@ -1177,7 +1176,8 @@
virtual const char* name() { return "DrawRects"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
}
@@ -1289,7 +1289,8 @@
return renderer.drawPath(mPath, getPaint(renderer));
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
SkPaint* paint = getPaint(renderer);
renderer.getCaches().pathCache.precache(mPath, paint);
@@ -1324,7 +1325,8 @@
virtual const char* name() { return "DrawLines"; }
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
deferInfo.batchId = mPaint->isAntiAlias() ?
DeferredDisplayList::kOpBatch_AlphaVertices :
DeferredDisplayList::kOpBatch_Vertices;
@@ -1360,7 +1362,8 @@
OP_LOG("Draw some text, %d bytes", mBytesCount);
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
SkPaint* paint = getPaint(renderer);
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
fontRenderer.precache(paint, mText, mCount, mat4::identity());
@@ -1425,7 +1428,8 @@
memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
}
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo) {
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
SkPaint* paint = getPaint(renderer);
FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
@@ -1448,19 +1452,20 @@
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
Rect bounds;
- getLocalBounds(bounds);
+ getLocalBounds(renderer.getDrawModifiers(), bounds);
return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
mPositions, getPaint(renderer), mTotalAdvance, bounds);
}
virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<DrawOp*>& ops, const Rect& bounds) {
+ const Vector<OpStatePair>& ops, const Rect& bounds) {
status_t status = DrawGlInfo::kStatusDone;
for (unsigned int i = 0; i < ops.size(); i++) {
+ const DeferredDisplayState& state = *(ops[i].state);
DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
- renderer.restoreDisplayState(ops[i]->state, true); // restore all but the clip
+ renderer.restoreDisplayState(state, true); // restore all but the clip
- DrawTextOp& op = *((DrawTextOp*)ops[i]);
+ DrawTextOp& op = *((DrawTextOp*)ops[i].op);
// quickReject() will not occure in drawText() so we can use mLocalBounds
// directly, we do not need to account for shadow by calling getLocalBounds()
status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 90dcf93..8866029 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -505,17 +505,12 @@
void DisplayListRenderer::addDrawOp(DrawOp* op) {
Rect localBounds;
- if (mDrawModifiers.mHasShadow) {
- op->state.mDrawModifiers = mDrawModifiers;
- }
- if (op->getLocalBounds(localBounds)) {
+ if (op->getLocalBounds(mDrawModifiers, localBounds)) {
bool rejected = quickRejectNoScissor(localBounds.left, localBounds.top,
localBounds.right, localBounds.bottom);
op->setQuickRejected(rejected);
}
- if (mDrawModifiers.mHasShadow) {
- op->state.mDrawModifiers.reset();
- }
+
mHasDrawOps = true;
addOpInternal(op);
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 54f6d76..f74df97 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,24 +98,11 @@
kClipSide_ConservativeFull = 0x1F
};
-struct DeferredDisplayState {
- // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
- Rect mBounds;
-
- // the below are set and used by the OpenGLRenderer at record and deferred playback
- bool mClipValid;
- Rect mClip;
- int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
- bool mClipped;
- mat4 mMatrix;
- DrawModifiers mDrawModifiers;
- float mAlpha;
-};
-
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
+class DeferredDisplayState;
class DisplayList;
class TextSetupFunctor;
class VertexBuffer;
@@ -423,7 +410,7 @@
return getXfermode(paint->getXfermode());
}
- static inline int getAlphaDirect(SkPaint* paint) {
+ static inline int getAlphaDirect(const SkPaint* paint) {
if (!paint) return 255;
return paint->getAlpha();
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
index 7d6ca56..e47bf0c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -57,7 +57,7 @@
public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private static final String LOG_TAG = "FusedPrintersProvider";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private static final double WEIGHT_DECAY_COEFFICIENT = 0.95f;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 1040edf..514e8ca 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -42,6 +42,7 @@
import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentAdapter;
@@ -341,7 +342,11 @@
if (!mController.hasStarted()) {
mController.start();
}
- if (!printAttributesChanged() && mDocument.info != null) {
+ if (!printAttributesChanged()) {
+ if (mDocument.info == null) {
+ // We are waiting for the result of a layout, so do nothing.
+ return;
+ }
// If the attributes didn't change and we have done a layout, then
// we do not do a layout but may have to ask the app to write some
// pages. Hence, pretend layout completed and nothing changed, so
@@ -738,6 +743,8 @@
private PrinterInfo mCurrentPrinter;
+ private boolean mRequestedCurrentPrinterRefresh;
+
private final OnItemSelectedListener mOnItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@Override
@@ -757,34 +764,34 @@
return;
}
- mCurrPrintAttributes.clear();
+ mRequestedCurrentPrinterRefresh = false;
- PrinterInfo printer = (PrinterInfo) mDestinationSpinnerAdapter
+ mCurrentPrinter = (PrinterInfo) mDestinationSpinnerAdapter
.getItem(position);
PrintSpoolerService.peekInstance().setPrintJobPrinterNoPersistence(
- mPrintJobId, printer);
+ mPrintJobId, mCurrentPrinter);
- if (printer != null) {
- PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
- if (capabilities == null) {
- //TODO: We need a timeout for the update.
- mEditor.refreshCurrentPrinter();
- } else {
- capabilities.getDefaults(mCurrPrintAttributes);
- if (!mController.hasStarted()) {
- mController.start();
- }
- mController.update();
- }
+ if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) {
+ updateUi();
+ return;
}
- mCurrentPrinter = printer;
-
- updateUiForNewPrinterCapabilities();
+ PrinterCapabilitiesInfo capabilities = mCurrentPrinter.getCapabilities();
+ if (capabilities == null) {
+ // TODO: We need a timeout for the update.
+ mRequestedCurrentPrinterRefresh = true;
+ updateUi();
+ refreshCurrentPrinter();
+ } else {
+ updatePrintAttributes(capabilities);
+ updateUi();
+ mController.update();
+ }
} else if (spinner == mMediaSizeSpinner) {
- if (mIgnoreNextMediaSizeChange) {
- mIgnoreNextMediaSizeChange = false;
+ if (mOldMediaSizeSelectionIndex
+ == mMediaSizeSpinner.getSelectedItemPosition()) {
+ mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION;
return;
}
SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
@@ -793,8 +800,9 @@
mController.update();
}
} else if (spinner == mColorModeSpinner) {
- if (mIgnoreNextColorModeChange) {
- mIgnoreNextColorModeChange = false;
+ if (mOldColorModeSelectionIndex
+ == mColorModeSpinner.getSelectedItemPosition()) {
+ mOldColorModeSelectionIndex = AdapterView.INVALID_POSITION;
return;
}
SpinnerItem<Integer> colorModeItem =
@@ -810,16 +818,7 @@
}
SpinnerItem<Integer> orientationItem =
mOrientationSpinnerAdapter.getItem(position);
- MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
- if (orientationItem.value == ORIENTATION_PORTRAIT) {
- if (!mediaSize.isPortrait()) {
- mCurrPrintAttributes.setMediaSize(mediaSize.asPortrait());
- }
- } else {
- if (mediaSize.isPortrait()) {
- mCurrPrintAttributes.setMediaSize(mediaSize.asLandscape());
- }
- }
+ setCurrentPrintAttributesOrientation(orientationItem.value);
if (!hasErrors()) {
mController.update();
}
@@ -841,6 +840,105 @@
}
};
+ private void setCurrentPrintAttributesOrientation(int orientation) {
+ MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
+ if (orientation == ORIENTATION_PORTRAIT) {
+ if (!mediaSize.isPortrait()) {
+ // Rotate the media size.
+ mCurrPrintAttributes.setMediaSize(mediaSize.asPortrait());
+
+ // Rotate the resolution.
+ Resolution oldResolution = mCurrPrintAttributes.getResolution();
+ Resolution newResolution = new Resolution(
+ oldResolution.getId(),
+ oldResolution.getLabel(getPackageManager()),
+ oldResolution.getVerticalDpi(),
+ oldResolution.getHorizontalDpi());
+ mCurrPrintAttributes.setResolution(newResolution);
+
+ // Rotate the physical margins.
+ Margins oldMargins = mCurrPrintAttributes.getMargins();
+ Margins newMargins = new Margins(
+ oldMargins.getBottomMils(),
+ oldMargins.getLeftMils(),
+ oldMargins.getTopMils(),
+ oldMargins.getRightMils());
+ mCurrPrintAttributes.setMargins(newMargins);
+ }
+ } else {
+ if (mediaSize.isPortrait()) {
+ // Rotate the media size.
+ mCurrPrintAttributes.setMediaSize(mediaSize.asLandscape());
+
+ // Rotate the resolution.
+ Resolution oldResolution = mCurrPrintAttributes.getResolution();
+ Resolution newResolution = new Resolution(
+ oldResolution.getId(),
+ oldResolution.getLabel(getPackageManager()),
+ oldResolution.getVerticalDpi(),
+ oldResolution.getHorizontalDpi());
+ mCurrPrintAttributes.setResolution(newResolution);
+
+ // Rotate the physical margins.
+ Margins oldMargins = mCurrPrintAttributes.getMargins();
+ Margins newMargins = new Margins(
+ oldMargins.getTopMils(),
+ oldMargins.getRightMils(),
+ oldMargins.getBottomMils(),
+ oldMargins.getLeftMils());
+ mCurrPrintAttributes.setMargins(newMargins);
+ }
+ }
+ }
+
+ private void updatePrintAttributes(PrinterCapabilitiesInfo capabilities) {
+ PrintAttributes defaults = mTempPrintAttributes;
+ capabilities.getDefaults(defaults);
+
+ // Media size.
+ MediaSize currMediaSize = mCurrPrintAttributes.getMediaSize();
+ if (currMediaSize == null) {
+ mCurrPrintAttributes.setMediaSize(defaults.getMediaSize());
+ } else {
+ MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
+ List<MediaSize> mediaSizes = capabilities.getMediaSizes();
+ final int mediaSizeCount = mediaSizes.size();
+ for (int i = 0; i < mediaSizeCount; i++) {
+ MediaSize mediaSize = mediaSizes.get(i);
+ if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
+ mCurrPrintAttributes.setMediaSize(mediaSize);
+ break;
+ }
+ }
+ }
+
+ // Color mode.
+ final int colorMode = mCurrPrintAttributes.getColorMode();
+ if ((capabilities.getColorModes() & colorMode) == 0) {
+ mCurrPrintAttributes.setColorMode(colorMode);
+ }
+
+ // Resolution
+ Resolution resolution = mCurrPrintAttributes.getResolution();
+ if (resolution == null || !capabilities.getResolutions().contains(resolution)) {
+ mCurrPrintAttributes.setResolution(defaults.getResolution());
+ }
+
+ // Margins.
+ Margins margins = mCurrPrintAttributes.getMargins();
+ if (margins == null) {
+ mCurrPrintAttributes.setMargins(defaults.getMargins());
+ } else {
+ Margins minMargins = capabilities.getMinMargins();
+ if (margins.getLeftMils() < minMargins.getLeftMils()
+ || margins.getTopMils() < minMargins.getTopMils()
+ || margins.getRightMils() > minMargins.getRightMils()
+ || margins.getBottomMils() > minMargins.getBottomMils()) {
+ mCurrPrintAttributes.setMargins(defaults.getMargins());
+ }
+ }
+ }
+
private final TextWatcher mCopiesTextWatcher = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
@@ -952,8 +1050,8 @@
private int mEditorState;
private boolean mIgnoreNextDestinationChange;
- private boolean mIgnoreNextMediaSizeChange;
- private boolean mIgnoreNextColorModeChange;
+ private int mOldMediaSizeSelectionIndex;
+ private int mOldColorModeSelectionIndex;
private boolean mIgnoreNextOrientationChange;
private boolean mIgnoreNextRangeOptionChange;
private boolean mIgnoreNextCopiesChange;
@@ -993,11 +1091,22 @@
// capabilities, we refresh it.
if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE
&& printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
- && printer.getCapabilities() == null) {
+ && printer.getCapabilities() == null
+ && !mRequestedCurrentPrinterRefresh) {
+ mRequestedCurrentPrinterRefresh = true;
refreshCurrentPrinter();
return;
}
+ // We just refreshed the current printer.
+ if (printer.getCapabilities() != null
+ && mRequestedCurrentPrinterRefresh) {
+ mRequestedCurrentPrinterRefresh = false;
+ updatePrintAttributes(printer.getCapabilities());
+ updateUi();
+ mController.update();
+ }
+
// Update the UI if capabilities changed.
boolean capabilitiesChanged = false;
@@ -1010,14 +1119,18 @@
capabilitiesChanged = true;
}
- if (capabilitiesChanged) {
- // Update the current printer.
- mCurrentPrinter.copyFrom(printer);
+ // Update the UI if the status changed.
+ final boolean statusChanged = mCurrentPrinter.getStatus()
+ != printer.getStatus();
- // If something changed during UI update...
+ // Update the printer with the latest info.
+ if (!mCurrentPrinter.equals(printer)) {
+ mCurrentPrinter.copyFrom(printer);
+ }
+
+ if (capabilitiesChanged || statusChanged) {
+ // If something changed during update...
if (updateUi()) {
- // Update current attributes.
- printer.getCapabilities().getDefaults(mCurrPrintAttributes);
// Update the document.
mController.update();
}
@@ -1031,7 +1144,7 @@
@Override
public void onInvalidated() {
- updateUiForNewPrinterCapabilities();
+ /* do nothing - we always have one fake PDF printer */
}
});
@@ -1072,6 +1185,10 @@
showUi(UI_EDITING_PRINT_JOB, null);
bindUi();
+
+ mCurrentPrinter = mDestinationSpinnerAdapter.mFakePdfPrinter;
+ updatePrintAttributes(mCurrentPrinter.getCapabilities());
+
updateUi();
}
@@ -1393,7 +1510,7 @@
mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
if (mMediaSizeSpinnerAdapter.getCount() > 0) {
- mIgnoreNextMediaSizeChange = true;
+ mOldMediaSizeSelectionIndex = 0;
}
// Color mode.
@@ -1401,7 +1518,7 @@
mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
if (mColorModeSpinnerAdapter.getCount() > 0) {
- mIgnoreNextColorModeChange = true;
+ mOldColorModeSelectionIndex = 0;
}
// Orientation
@@ -1454,7 +1571,8 @@
Object item = mDestinationSpinnerAdapter.getItem(selectedIndex);
if (item instanceof PrinterInfo) {
PrinterInfo printer = (PrinterInfo) item;
- if (printer.getCapabilities() != null) {
+ if (printer.getCapabilities() != null
+ && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE) {
allOptionsEnabled = true;
}
}
@@ -1470,14 +1588,14 @@
// Media size
if (mMediaSizeSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION) {
- mIgnoreNextMediaSizeChange = true;
+ mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION;
mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION);
}
mMediaSizeSpinner.setEnabled(false);
// Color mode
if (mColorModeSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION) {
- mIgnoreNextColorModeChange = true;
+ mOldColorModeSelectionIndex = AdapterView.INVALID_POSITION;
mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
}
mColorModeSpinner.setEnabled(false);
@@ -1513,9 +1631,9 @@
} else {
boolean someAttributeSelectionChanged = false;
- PrintAttributes defaultAttributes = mTempPrintAttributes;
PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
+ PrintAttributes defaultAttributes = mTempPrintAttributes;
printer.getCapabilities().getDefaults(defaultAttributes);
// Media size.
@@ -1551,25 +1669,19 @@
mediaSize, mediaSize.getLabel(getPackageManager())));
}
- if (mediaSizeCount <= 0) {
- // No media sizes - clear the selection.
- mMediaSizeSpinner.setEnabled(false);
- // Clear selection and mark if selection changed.
- someAttributeSelectionChanged = setMediaSizeSpinnerSelectionNoCallback(
- AdapterView.INVALID_POSITION);
- } else {
- mMediaSizeSpinner.setEnabled(true);
+ mMediaSizeSpinner.setEnabled(true);
- if (oldMediaSizeNewIndex != AdapterView.INVALID_POSITION) {
- // Select the old media size - nothing really changed.
- setMediaSizeSpinnerSelectionNoCallback(oldMediaSizeNewIndex);
- } else {
- // Select the first or the default and mark if selection changed.
- final int mediaSizeIndex = Math.max(mediaSizes.indexOf(
- defaultAttributes.getMediaSize()), 0);
- someAttributeSelectionChanged = setMediaSizeSpinnerSelectionNoCallback(
- mediaSizeIndex);
- }
+ if (oldMediaSizeNewIndex != AdapterView.INVALID_POSITION) {
+ // Select the old media size - nothing really changed.
+ setMediaSizeSpinnerSelectionNoCallback(oldMediaSizeNewIndex);
+ } else {
+ // Select the first or the default and mark if selection changed.
+ final int mediaSizeIndex = Math.max(mediaSizes.indexOf(
+ defaultAttributes.getMediaSize()), 0);
+ setMediaSizeSpinnerSelectionNoCallback(mediaSizeIndex);
+ mCurrPrintAttributes.setMediaSize(mMediaSizeSpinnerAdapter
+ .getItem(mediaSizeIndex).value);
+ someAttributeSelectionChanged = true;
}
}
mMediaSizeSpinner.setEnabled(true);
@@ -1618,26 +1730,32 @@
mColorModeSpinnerAdapter.add(new SpinnerItem<Integer>(colorMode,
colorModeLabels[colorBitOffset]));
}
- final int colorModeCount = Integer.bitCount(colorModes);
- if (colorModeCount <= 0) {
- mColorModeSpinner.setEnabled(false);
- mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
+ mColorModeSpinner.setEnabled(true);
+ if (oldColorModeNewIndex != AdapterView.INVALID_POSITION) {
+ // Select the old color mode - nothing really changed.
+ setColorModeSpinnerSelectionNoCallback(oldColorModeNewIndex);
} else {
- mColorModeSpinner.setEnabled(true);
- if (oldColorModeNewIndex != AdapterView.INVALID_POSITION) {
- // Select the old color mode - nothing really changed.
- setColorModeSpinnerSelectionNoCallback(oldColorModeNewIndex);
- } else {
- final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
+ final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
(colorModes & defaultAttributes.getColorMode()));
- someAttributeSelectionChanged = setColorModeSpinnerSelectionNoCallback(
- selectedColorModeIndex);
- }
+ setColorModeSpinnerSelectionNoCallback(selectedColorModeIndex);
+ mCurrPrintAttributes.setColorMode(mColorModeSpinnerAdapter
+ .getItem(selectedColorModeIndex).value);
+ someAttributeSelectionChanged = true;
}
}
mColorModeSpinner.setEnabled(true);
// Orientation
+ MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
+ if (mediaSize.isPortrait()
+ && mOrientationSpinner.getSelectedItemPosition() != 0) {
+ mIgnoreNextOrientationChange = true;
+ mOrientationSpinner.setSelection(0);
+ } else if (!mediaSize.isPortrait()
+ && mOrientationSpinner.getSelectedItemPosition() != 1) {
+ mIgnoreNextOrientationChange = true;
+ mOrientationSpinner.setSelection(1);
+ }
mOrientationSpinner.setEnabled(true);
// Range options
@@ -1723,50 +1841,18 @@
}
}
- private boolean setMediaSizeSpinnerSelectionNoCallback(int position) {
+ private void setMediaSizeSpinnerSelectionNoCallback(int position) {
if (mMediaSizeSpinner.getSelectedItemPosition() != position) {
- mIgnoreNextMediaSizeChange = true;
+ mOldMediaSizeSelectionIndex = position;
mMediaSizeSpinner.setSelection(position);
- return true;
}
- return false;
}
- private boolean setColorModeSpinnerSelectionNoCallback(int position) {
+ private void setColorModeSpinnerSelectionNoCallback(int position) {
if (mColorModeSpinner.getSelectedItemPosition() != position) {
- mIgnoreNextColorModeChange = true;
+ mOldColorModeSelectionIndex = position;
mColorModeSpinner.setSelection(position);
- return true;
}
- return false;
- }
-
- private void updateUiForNewPrinterCapabilities() {
- // The printer changed so we want to start with a clean slate
- // for the print options and let them be populated from the
- // printer capabilities and use the printer defaults.
- if (!mMediaSizeSpinnerAdapter.isEmpty()) {
- mIgnoreNextMediaSizeChange = true;
- mMediaSizeSpinnerAdapter.clear();
- }
- if (!mColorModeSpinnerAdapter.isEmpty()) {
- mIgnoreNextColorModeChange = true;
- mColorModeSpinnerAdapter.clear();
- }
- if (mOrientationSpinner.getSelectedItemPosition() != 0) {
- mIgnoreNextOrientationChange = true;
- mOrientationSpinner.setSelection(0);
- }
- if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
- mIgnoreNextRangeOptionChange = true;
- mRangeOptionsSpinner.setSelection(0);
- }
- if (!TextUtils.isEmpty(mCopiesEditText.getText())) {
- mIgnoreNextCopiesChange = true;
- mCopiesEditText.setText(MIN_COPIES_STRING);
- }
-
- updateUi();
}
private void startSelectPrinterActivity() {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 7266af8..76e548a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -73,9 +73,9 @@
private static final String LOG_TAG = "PrintSpoolerService";
- private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true;
+ private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
- private static final boolean DEBUG_PERSISTENCE = true;
+ private static final boolean DEBUG_PERSISTENCE = false;
private static final boolean PERSISTNECE_MANAGER_ENABLED = true;
@@ -838,18 +838,8 @@
resolution.getHorizontalDpi()));
serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
resolution.getVerticalDpi()));
- // We prefer to store only the package name and
- // resource id and fallback to the label.
- if (!TextUtils.isEmpty(mediaSize.mPackageName)
- && resolution.mLabelResId > 0) {
- serializer.attribute(null, ATTR_PACKAGE_NAME,
- resolution.mPackageName);
- serializer.attribute(null, ATTR_LABEL_RES_ID,
- String.valueOf(resolution.mLabelResId));
- } else {
- serializer.attribute(null, ATTR_LABEL,
- resolution.getLabel(getPackageManager()));
- }
+ serializer.attribute(null, ATTR_LABEL,
+ resolution.getLabel(getPackageManager()));
serializer.endTag(null, TAG_RESOLUTION);
}
@@ -1047,11 +1037,7 @@
ATTR_HORIZONTAL_DPI));
final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
ATTR_VERTICAL_DPI));
- String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- final int labelResId = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_LABEL_RES_ID));
- Resolution resolution = new Resolution(id, label, packageName, labelResId,
- horizontalDpi, verticalDpi);
+ Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
builder.setResolution(resolution);
parser.next();
skipEmptyTextTags(parser);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
index 4006a5a..fd14af9 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -17,7 +17,6 @@
package com.android.printspooler;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -43,7 +42,7 @@
final class RemotePrintDocumentAdapter {
private static final String LOG_TAG = "RemotePrintDocumentAdapter";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private final IPrintDocumentAdapter mRemoteInterface;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 344446f..7b09092 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 @@
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 @@
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 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 a3bd785..11913ee 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.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 @@
@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 @@
}
}
- 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 @@
@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 @@
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 @@
}
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/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java
index 60893b8..fab84a8 100644
--- a/services/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/java/com/android/server/location/FlpHardwareProvider.java
@@ -26,6 +26,7 @@
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
+import android.location.LocationRequest;
import android.content.Context;
import android.os.Bundle;
@@ -73,10 +74,19 @@
// register for listening for passive provider data
LocationManager manager = (LocationManager) mContext.getSystemService(
Context.LOCATION_SERVICE);
- manager.requestLocationUpdates(
+ final long minTime = 0;
+ final float minDistance = 0;
+ final boolean oneShot = false;
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(
LocationManager.PASSIVE_PROVIDER,
- 0 /* minTime */,
- 0 /* minDistance */,
+ minTime,
+ minDistance,
+ oneShot);
+ // Don't keep track of this request since it's done on behalf of other clients
+ // (which are kept track of separately).
+ request.setHideFromAppOps(true);
+ manager.requestLocationUpdates(
+ request,
new NetworkLocationListener(),
Looper.myLooper());
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 6053c61..9c76c19 100644
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -512,8 +512,21 @@
public void run() {
LocationManager locManager =
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
- 0, 0, new NetworkLocationListener(), mHandler.getLooper());
+ final long minTime = 0;
+ final float minDistance = 0;
+ final boolean oneShot = false;
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(
+ LocationManager.PASSIVE_PROVIDER,
+ minTime,
+ minDistance,
+ oneShot);
+ // Don't keep track of this request since it's done on behalf of other clients
+ // (which are kept track of separately).
+ request.setHideFromAppOps(true);
+ locManager.requestLocationUpdates(
+ request,
+ new NetworkLocationListener(),
+ mHandler.getLooper());
}
});
}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index b5010f2..976a328 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -29,7 +29,6 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-import android.hardware.SystemSensorManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -119,7 +118,7 @@
// Proximity sensor debounce delay in milliseconds for positive or negative transitions.
private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
- private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
+ private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
@@ -164,6 +163,10 @@
// Notifier for sending asynchronous notifications.
private final Notifier mNotifier;
+ // The display suspend blocker.
+ // Held while there are pending state change notifications.
+ private final SuspendBlocker mDisplaySuspendBlocker;
+
// The display blanker.
private final DisplayBlanker mDisplayBlanker;
@@ -271,7 +274,7 @@
// The raw non-debounced proximity sensor state.
private int mPendingProximity = PROXIMITY_UNKNOWN;
- private long mPendingProximityDebounceTime;
+ private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
// True if the screen was turned off because of the proximity sensor.
// When the screen turns on again, we report user activity to the power manager.
@@ -346,10 +349,11 @@
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
LightsService lights, TwilightService twilight, SensorManager sensorManager,
DisplayManagerService displayManager,
- DisplayBlanker displayBlanker,
+ SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
mNotifier = notifier;
+ mDisplaySuspendBlocker = displaySuspendBlocker;
mDisplayBlanker = displayBlanker;
mCallbacks = callbacks;
mCallbackHandler = callbackHandler;
@@ -601,7 +605,7 @@
if (!mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = true;
- sendOnProximityPositive();
+ sendOnProximityPositiveWithWakelock();
setScreenOn(false);
}
} else if (mWaitingForNegativeProximity
@@ -616,7 +620,7 @@
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = false;
- sendOnProximityNegative();
+ sendOnProximityNegativeWithWakelock();
}
} else {
mWaitingForNegativeProximity = false;
@@ -737,7 +741,7 @@
}
}
}
- sendOnStateChanged();
+ sendOnStateChangedWithWakelock();
}
}
@@ -810,49 +814,67 @@
private void setProximitySensorEnabled(boolean enable) {
if (enable) {
if (!mProximitySensorEnabled) {
+ // Register the listener.
+ // Proximity sensor state already cleared initially.
mProximitySensorEnabled = true;
- mPendingProximity = PROXIMITY_UNKNOWN;
mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
SensorManager.SENSOR_DELAY_NORMAL, mHandler);
}
} else {
if (mProximitySensorEnabled) {
+ // Unregister the listener.
+ // Clear the proximity sensor state for next time.
mProximitySensorEnabled = false;
mProximity = PROXIMITY_UNKNOWN;
+ mPendingProximity = PROXIMITY_UNKNOWN;
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mProximitySensorListener);
+ clearPendingProximityDebounceTime(); // release wake lock (must be last)
}
}
}
private void handleProximitySensorEvent(long time, boolean positive) {
- if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
- return; // no change
- }
- if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
- return; // no change
- }
+ if (mProximitySensorEnabled) {
+ if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
+ return; // no change
+ }
+ if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
+ return; // no change
+ }
- // Only accept a proximity sensor reading if it remains
- // stable for the entire debounce delay.
- mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
- if (positive) {
- mPendingProximity = PROXIMITY_POSITIVE;
- mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
- } else {
- mPendingProximity = PROXIMITY_NEGATIVE;
- mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
+ // Only accept a proximity sensor reading if it remains
+ // stable for the entire debounce delay. We hold a wake lock while
+ // debouncing the sensor.
+ mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
+ if (positive) {
+ mPendingProximity = PROXIMITY_POSITIVE;
+ setPendingProximityDebounceTime(
+ time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
+ } else {
+ mPendingProximity = PROXIMITY_NEGATIVE;
+ setPendingProximityDebounceTime(
+ time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
+ }
+
+ // Debounce the new sensor reading.
+ debounceProximitySensor();
}
- debounceProximitySensor();
}
private void debounceProximitySensor() {
- if (mPendingProximity != PROXIMITY_UNKNOWN) {
+ if (mProximitySensorEnabled
+ && mPendingProximity != PROXIMITY_UNKNOWN
+ && mPendingProximityDebounceTime >= 0) {
final long now = SystemClock.uptimeMillis();
if (mPendingProximityDebounceTime <= now) {
+ // Sensor reading accepted. Apply the change then release the wake lock.
mProximity = mPendingProximity;
- sendUpdatePowerState();
+ updatePowerState();
+ clearPendingProximityDebounceTime(); // release wake lock (must be last)
} else {
+ // Need to wait a little longer.
+ // Debounce again later. We continue holding a wake lock while waiting.
Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
@@ -860,6 +882,20 @@
}
}
+ private void clearPendingProximityDebounceTime() {
+ if (mPendingProximityDebounceTime >= 0) {
+ mPendingProximityDebounceTime = -1;
+ mDisplaySuspendBlocker.release(); // release wake lock
+ }
+ }
+
+ private void setPendingProximityDebounceTime(long debounceTime) {
+ if (mPendingProximityDebounceTime < 0) {
+ mDisplaySuspendBlocker.acquire(); // acquire wake lock
+ }
+ mPendingProximityDebounceTime = debounceTime;
+ }
+
private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
if (enable) {
if (!mLightSensorEnabled) {
@@ -1120,7 +1156,8 @@
return x + (y - x) * alpha;
}
- private void sendOnStateChanged() {
+ private void sendOnStateChangedWithWakelock() {
+ mDisplaySuspendBlocker.acquire();
mCallbackHandler.post(mOnStateChangedRunnable);
}
@@ -1128,10 +1165,12 @@
@Override
public void run() {
mCallbacks.onStateChanged();
+ mDisplaySuspendBlocker.release();
}
};
- private void sendOnProximityPositive() {
+ private void sendOnProximityPositiveWithWakelock() {
+ mDisplaySuspendBlocker.acquire();
mCallbackHandler.post(mOnProximityPositiveRunnable);
}
@@ -1139,10 +1178,12 @@
@Override
public void run() {
mCallbacks.onProximityPositive();
+ mDisplaySuspendBlocker.release();
}
};
- private void sendOnProximityNegative() {
+ private void sendOnProximityNegativeWithWakelock() {
+ mDisplaySuspendBlocker.acquire();
mCallbackHandler.post(mOnProximityNegativeRunnable);
}
@@ -1150,6 +1191,7 @@
@Override
public void run() {
mCallbacks.onProximityNegative();
+ mDisplaySuspendBlocker.release();
}
};
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 2167f67..fe09a33 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -63,7 +63,6 @@
import android.view.WindowManagerPolicy;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -287,6 +286,9 @@
// True if the device should wake up when plugged or unplugged.
private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
+ // True if the device should suspend when the screen is off due to proximity.
+ private boolean mSuspendWhenScreenOffDueToProximityConfig;
+
// True if dreams are supported on this device.
private boolean mDreamsSupportedConfig;
@@ -447,7 +449,7 @@
// own handler thread to ensure timely operation.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
mContext, mNotifier, mLightsService, twilight, sensorManager,
- mDisplayManagerService, mDisplayBlanker,
+ mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
mDisplayPowerControllerCallbacks, mHandler);
mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
@@ -514,6 +516,8 @@
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
+ mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
mDreamsSupportedConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsSupported);
mDreamsEnabledByDefaultConfig = resources.getBoolean(
@@ -639,6 +643,7 @@
}
}
+ @SuppressWarnings("deprecation")
private static boolean isScreenLock(final WakeLock wakeLock) {
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
@@ -817,6 +822,7 @@
}
}
+ @SuppressWarnings("deprecation")
private boolean isWakeLockLevelSupportedInternal(int level) {
synchronized (mLock) {
switch (level) {
@@ -1005,6 +1011,7 @@
}
}
+ @SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
@@ -1261,6 +1268,7 @@
*
* This function must have no other side-effects.
*/
+ @SuppressWarnings("deprecation")
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
@@ -1299,7 +1307,7 @@
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
if (mWakefulness != WAKEFULNESS_ASLEEP) {
- mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+ mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
break;
}
@@ -1458,7 +1466,11 @@
/**
* Returns true if the device is being kept awake by a wake lock, user activity
- * or the stay on while powered setting.
+ * or the stay on while powered setting. We also keep the phone awake when
+ * the proximity sensor returns a positive result so that the device does not
+ * lock while in a phone call. This function only controls whether the device
+ * will go to sleep or dream which is independent of whether it will be allowed
+ * to suspend.
*/
private boolean isBeingKeptAwakeLocked() {
return mStayOn
@@ -1749,10 +1761,8 @@
* This function must have no other side-effects.
*/
private void updateSuspendBlockerLocked() {
- final boolean needWakeLockSuspendBlocker = (mWakeLockSummary != 0);
- final boolean needDisplaySuspendBlocker = (mUserActivitySummary != 0
- || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
- || !mDisplayReady || !mBootCompleted);
+ final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
+ final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1775,6 +1785,27 @@
}
}
+ /**
+ * Return true if we must keep a suspend blocker active on behalf of the display.
+ * We do so if the screen is on or is in transition between states.
+ */
+ private boolean needDisplaySuspendBlocker() {
+ if (!mDisplayReady) {
+ return true;
+ }
+ if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ // If we asked for the screen to be on but it is off due to the proximity
+ // sensor then we may suspend but only if the configuration allows it.
+ // On some hardware it may not be safe to suspend because the proximity
+ // sensor may not be correctly configured as a wake-up source.
+ if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
+ || !mSuspendWhenScreenOffDueToProximityConfig) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override // Binder call
public boolean isScreenOn() {
final long ident = Binder.clearCallingIdentity();
@@ -2115,7 +2146,7 @@
*
* @param brightness The overridden brightness.
*
- * @see Settings.System#SCREEN_BRIGHTNESS
+ * @see android.provider.Settings.System#SCREEN_BRIGHTNESS
*/
@Override // Binder call
public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
@@ -2255,7 +2286,16 @@
pw.println();
pw.println("Settings and Configuration:");
+ pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig="
+ + mWakeUpWhenPluggedOrUnpluggedConfig);
+ pw.println(" mSuspendWhenScreenOffDueToProximityConfig="
+ + mSuspendWhenScreenOffDueToProximityConfig);
pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig);
+ pw.println(" mDreamsEnabledByDefaultConfig=" + mDreamsEnabledByDefaultConfig);
+ pw.println(" mDreamsActivatedOnSleepByDefaultConfig="
+ + mDreamsActivatedOnSleepByDefaultConfig);
+ pw.println(" mDreamsActivatedOnDockByDefaultConfig="
+ + mDreamsActivatedOnDockByDefaultConfig);
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index ddff0ae..f15c760 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -21,11 +21,9 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
-import android.os.AsyncTask;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -39,8 +37,6 @@
import android.printservice.IPrintServiceClient;
import android.util.Slog;
-import com.android.internal.R;
-
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -55,7 +51,7 @@
private static final String LOG_TAG = "RemotePrintService";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private final Context mContext;
@@ -65,7 +61,7 @@
private final RemotePrintSpooler mSpooler;
- private final UserState mUserState;
+ private final PrintServiceCallbacks mCallbacks;
private final int mUserId;
@@ -83,14 +79,24 @@
private boolean mDestroyed;
- private boolean mAllPrintJobsHandled;
+ private boolean mHasActivePrintJobs;
private boolean mHasPrinterDiscoverySession;
+ private List<PrinterId> mDiscoveryPriorityList;
+
+ private List<PrinterId> mTrackedPrinterList;
+
+ public static interface PrintServiceCallbacks {
+ public void onPrintersAdded(List<PrinterInfo> printers);
+ public void onPrintersRemoved(List<PrinterId> printerIds);
+ public void onServiceDied(RemotePrintService service);
+ }
+
public RemotePrintService(Context context, ComponentName componentName, int userId,
- RemotePrintSpooler spooler, UserState userState) {
+ RemotePrintSpooler spooler, PrintServiceCallbacks callbacks) {
mContext = context;
- mUserState = userState;
+ mCallbacks = callbacks;
mComponentName = componentName;
mIntent = new Intent().setComponent(mComponentName);
mUserId = userId;
@@ -99,15 +105,42 @@
mPrintServiceClient = new RemotePrintServiceClient(this);
}
+ public ComponentName getComponentName() {
+ return mComponentName;
+ }
+
public void destroy() {
mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY);
}
private void handleDestroy() {
throwIfDestroyed();
+
+ // Stop tracking printers.
+ if (mTrackedPrinterList != null) {
+ final int trackedPrinterCount = mTrackedPrinterList.size();
+ for (int i = 0; i < trackedPrinterCount; i++) {
+ PrinterId printerId = mTrackedPrinterList.get(i);
+ if (printerId.getServiceName().equals(mComponentName)) {
+ handleStopPrinterStateTracking(printerId);
+ }
+ }
+ }
+
+ // Stop printer discovery.
+ if (mDiscoveryPriorityList != null) {
+ handleStopPrinterDiscovery();
+ }
+
+ // Destroy the discovery session.
+ if (mHasPrinterDiscoverySession) {
+ handleDestroyPrinterDiscoverySession();
+ }
+
+ // Unbind.
ensureUnbound();
- mAllPrintJobsHandled = false;
- mHasPrinterDiscoverySession = false;
+
+ // Done
mDestroyed = true;
}
@@ -121,21 +154,9 @@
}
private void handleBinderDied() {
- mAllPrintJobsHandled = false;
- mHasPrinterDiscoverySession = false;
- mPendingCommands.clear();
- ensureUnbound();
-
- // Makes sure all active print jobs are failed since the service
- // just died. Do this off the main thread since we do to allow
- // calls into the spooler on the main thread.
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- failAllActivePrintJobs();
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ mPrintService.asBinder().unlinkToDeath(this, 0);
+ mPrintService = null;
+ mCallbacks.onServiceDied(this);
}
public void dump(PrintWriter pw, String prefix) {
@@ -148,32 +169,17 @@
pw.append(prefix).append(tab).append("bound=")
.append(String.valueOf(isBound())).println();
pw.append(prefix).append(tab).append("hasDicoverySession=")
- .append(String.valueOf(mHasPrinterDiscoverySession));
- }
-
- private void failAllActivePrintJobs() {
- List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName,
- PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
- if (printJobs == null) {
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- final int printJobCount = printJobs.size();
- for (int i = 0; i < printJobCount; i++) {
- PrintJobInfo printJob = printJobs.get(i);
- mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
- mContext.getString(R.string.reason_unknown));
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ .append(String.valueOf(mHasPrinterDiscoverySession)).println();
+ pw.append(prefix).append(tab).append("isDiscoveringPrinters=")
+ .append(String.valueOf(mDiscoveryPriorityList != null)).println();
+ pw.append(prefix).append(tab).append("trackedPrinters=")
+ .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null");
}
private void handleOnAllPrintJobsHandled() {
throwIfDestroyed();
- mAllPrintJobsHandled = true;
+ mHasActivePrintJobs = false;
if (isBound()) {
if (DEBUG) {
@@ -217,7 +223,7 @@
private void handleOnPrintJobQueued(final PrintJobInfo printJob) {
throwIfDestroyed();
- mAllPrintJobsHandled = false;
+ mHasActivePrintJobs = true;
if (!isBound()) {
ensureBound();
@@ -296,7 +302,7 @@
// If the service has no print jobs and no active discovery
// session anymore we should disconnect from it.
- if (mAllPrintJobsHandled) {
+ if (!mHasActivePrintJobs) {
ensureUnbound();
}
}
@@ -326,6 +332,11 @@
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error starting printer dicovery.", re);
}
+ // Take a note that we are doing discovery.
+ mDiscoveryPriorityList = new ArrayList<PrinterId>();
+ if (priorityList != null) {
+ mDiscoveryPriorityList.addAll(priorityList);
+ }
}
}
@@ -347,6 +358,8 @@
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()");
}
+ // We are not doing discovery anymore.
+ mDiscoveryPriorityList = null;
try {
mPrintService.stopPrinterDiscovery();
} catch (RemoteException re) {
@@ -406,6 +419,11 @@
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error requesting start printer tracking.", re);
}
+ // Take a note we are tracking the printer.
+ if (mTrackedPrinterList == null) {
+ mTrackedPrinterList = new ArrayList<PrinterId>();
+ }
+ mTrackedPrinterList.add(printerId);
}
}
@@ -428,6 +446,13 @@
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()");
}
+ // We are no longer tracking the printer.
+ if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) {
+ return;
+ }
+ if (mTrackedPrinterList.isEmpty()) {
+ mTrackedPrinterList = null;
+ }
try {
mPrintService.stopPrinterStateTracking(printerId);
} catch (RemoteException re) {
@@ -461,6 +486,10 @@
}
mBinding = false;
mPendingCommands.clear();
+ mHasActivePrintJobs = false;
+ mHasPrinterDiscoverySession = false;
+ mDiscoveryPriorityList = null;
+ mTrackedPrinterList = null;
if (isBound()) {
try {
mPrintService.setClient(null);
@@ -500,11 +529,31 @@
handleBinderDied();
return;
}
+ // If there is a session, then the service died after creating
+ // a session. Hence, recreate the session.
+ if (mHasPrinterDiscoverySession) {
+ handleCreatePrinterDiscoverySession();
+ }
+ // If there is a priority list, then the service died during
+ // discovery and is restarted. Hence, start discovery.
+ if (mDiscoveryPriorityList != null) {
+ handleStartPrinterDiscovery(mDiscoveryPriorityList);
+ }
+ // If there is a tracked printer list, then the service died
+ // during discovery and is restarted. Hence, start tracking.
+ if (mTrackedPrinterList != null) {
+ final int trackedPrinterCount = mTrackedPrinterList.size();
+ for (int i = 0; i < trackedPrinterCount; i++) {
+ handleStartPrinterStateTracking(mTrackedPrinterList.get(i));
+ }
+ }
+ // Finally, do all the pending work.
final int pendingCommandCount = mPendingCommands.size();
for (int i = 0; i < pendingCommandCount; i++) {
Runnable pendingCommand = mPendingCommands.get(i);
pendingCommand.run();
}
+ mPendingCommands.clear();
}
@Override
@@ -677,7 +726,7 @@
throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers);
final long identity = Binder.clearCallingIdentity();
try {
- service.mUserState.onPrintersAdded(printers);
+ service.mCallbacks.onPrintersAdded(printers);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -691,7 +740,7 @@
throwIfPrinterIdsTampered(service.mComponentName, printerIds);
final long identity = Binder.clearCallingIdentity();
try {
- service.mUserState.onPrintersRemoved(printerIds);
+ service.mCallbacks.onPrintersRemoved(printerIds);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index 28a6186..45469ac 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -21,7 +21,6 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
-import android.os.Build;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -57,7 +56,7 @@
private static final String LOG_TAG = "RemotePrintSpooler";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index 5392975..70fe370 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -23,7 +23,8 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.os.Build;
+import android.os.AsyncTask;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -32,6 +33,7 @@
import android.os.RemoteException;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintJobInfo;
+import android.print.PrintManager;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
@@ -43,7 +45,9 @@
import android.util.Log;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.os.SomeArgs;
+import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
import java.io.FileDescriptor;
@@ -58,11 +62,11 @@
/**
* Represents the print state for a user.
*/
-final class UserState implements PrintSpoolerCallbacks {
+final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
private static final String LOG_TAG = "UserState";
- private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private static final int MAX_ITEMS_PER_CALLBACK = 50;
@@ -246,6 +250,7 @@
}
}
+ @Override
public void onPrintersAdded(List<PrinterInfo> printers) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -257,11 +262,11 @@
if (mPrinterDiscoverySession == null) {
return;
}
- // Request an updated.
mPrinterDiscoverySession.onPrintersAddedLocked(printers);
}
}
+ @Override
public void onPrintersRemoved(List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -273,11 +278,28 @@
if (mPrinterDiscoverySession == null) {
return;
}
- // Request an updated.
mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds);
}
}
+ @Override
+ public void onServiceDied(RemotePrintService service) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ // No services - nothing to do.
+ if (mActiveServices.isEmpty()) {
+ return;
+ }
+ // Fail all print jobs.
+ failActivePrintJobsForService(service.getComponentName());
+ // No session - nothing to do.
+ if (mPrinterDiscoverySession == null) {
+ return;
+ }
+ mPrinterDiscoverySession.onServiceDiedLocked(service);
+ }
+ }
+
public void updateIfNeededLocked() {
throwIfDestroyedLocked();
if (readConfigurationLocked()) {
@@ -516,23 +538,72 @@
if (!mActiveServices.containsKey(serviceName)) {
RemotePrintService service = new RemotePrintService(
mContext, serviceName, mUserId, mSpooler, this);
- mActiveServices.put(serviceName, service);
- if (mPrinterDiscoverySession != null) {
- mPrinterDiscoverySession.onServiceAddedLocked(service);
- }
+ addServiceLocked(service);
}
} else {
RemotePrintService service = mActiveServices.remove(serviceName);
if (service != null) {
- service.destroy();
- if (mPrinterDiscoverySession != null) {
- mPrinterDiscoverySession.onServiceRemovedLocked(serviceName);
- }
+ removeServiceLocked(service);
}
}
}
}
+ private void addServiceLocked(RemotePrintService service) {
+ mActiveServices.put(service.getComponentName(), service);
+ if (mPrinterDiscoverySession != null) {
+ mPrinterDiscoverySession.onServiceAddedLocked(service);
+ }
+ }
+
+ private void removeServiceLocked(RemotePrintService service) {
+ // Fail all print jobs.
+ failActivePrintJobsForService(service.getComponentName());
+ // If discovery is in progress, tear down the service.
+ if (mPrinterDiscoverySession != null) {
+ mPrinterDiscoverySession.onServiceRemovedLocked(service);
+ } else {
+ // Otherwise, just destroy it.
+ service.destroy();
+ }
+ }
+
+ private void failActivePrintJobsForService(final ComponentName serviceName) {
+ // Makes sure all active print jobs are failed since the service
+ // just died. Do this off the main thread since we do to allow
+ // calls into the spooler on the main thread.
+ if (Looper.getMainLooper().isCurrentThread()) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ failActivePrintJobsForServiceInternal(serviceName);
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ } else {
+ failActivePrintJobsForServiceInternal(serviceName);
+ }
+ }
+
+ private void failActivePrintJobsForServiceInternal(ComponentName serviceName) {
+ List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(serviceName,
+ PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
+ if (printJobs == null) {
+ return;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final int printJobCount = printJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = printJobs.get(i);
+ mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+ mContext.getString(R.string.reason_unknown));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private void throwIfDestroyedLocked() {
if (mDestroyed) {
throw new IllegalStateException("Cannot interact with a destroyed instance.");
@@ -603,17 +674,18 @@
return;
}
- // If printer discovery is ongoing and the start request has a list
- // of printer to be checked, then we just request validating them.
- if (!mStartedPrinterDiscoveryTokens.isEmpty()
- && priorityList != null && !priorityList.isEmpty()) {
- validatePrinters(priorityList);
- return;
- }
+ final boolean discoveryStarted = !mStartedPrinterDiscoveryTokens.isEmpty();
// Remember we got a start request to match with an end.
mStartedPrinterDiscoveryTokens.add(observer.asBinder());
+ // If printer discovery is ongoing and the start request has a list
+ // of printer to be checked, then we just request validating them.
+ if (discoveryStarted && priorityList != null && !priorityList.isEmpty()) {
+ validatePrinters(priorityList);
+ return;
+ }
+
// The service are already performing discovery - nothing to do.
if (mStartedPrinterDiscoveryTokens.size() > 1) {
return;
@@ -822,32 +894,20 @@
}
}
- public void onServiceRemovedLocked(ComponentName serviceName) {
+ public void onServiceRemovedLocked(RemotePrintService service) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not updating removed service - session destroyed");
return;
}
- // No printers - nothing to do.
- if (mPrinters.isEmpty()) {
- return;
- }
- // Remove the printers for that service.
- List<PrinterId> removedPrinterIds = null;
- final int printerCount = mPrinters.size();
- for (int i = 0; i < printerCount; i++) {
- PrinterId printerId = mPrinters.keyAt(i);
- if (printerId.getServiceName().equals(serviceName)) {
- if (removedPrinterIds == null) {
- removedPrinterIds = new ArrayList<PrinterId>();
- }
- removedPrinterIds.add(printerId);
- }
- }
- if (!removedPrinterIds.isEmpty()) {
- mHandler.obtainMessage(
- SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
- removedPrinterIds).sendToTarget();
- }
+ // Remove the reported and tracked printers for that service.
+ ComponentName serviceName = service.getComponentName();
+ removePrintersForServiceLocked(serviceName);
+ service.destroy();
+ }
+
+ public void onServiceDiedLocked(RemotePrintService service) {
+ // Remove the reported by that service.
+ removePrintersForServiceLocked(service.getComponentName());
}
public void onServiceAddedLocked(RemotePrintService service) {
@@ -908,6 +968,34 @@
}
}
+ private void removePrintersForServiceLocked(ComponentName serviceName) {
+ // No printers - nothing to do.
+ if (mPrinters.isEmpty()) {
+ return;
+ }
+ // Remove the printers for that service.
+ List<PrinterId> removedPrinterIds = null;
+ final int printerCount = mPrinters.size();
+ for (int i = 0; i < printerCount; i++) {
+ PrinterId printerId = mPrinters.keyAt(i);
+ if (printerId.getServiceName().equals(serviceName)) {
+ if (removedPrinterIds == null) {
+ removedPrinterIds = new ArrayList<PrinterId>();
+ }
+ removedPrinterIds.add(printerId);
+ }
+ }
+ final int removedPrinterCount = removedPrinterIds.size();
+ for (int i = 0; i < removedPrinterCount; i++) {
+ mPrinters.remove(removedPrinterIds.get(i));
+ }
+ if (removedPrinterIds != null) {
+ mHandler.obtainMessage(
+ SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+ removedPrinterIds).sendToTarget();
+ }
+ }
+
private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) {
final int observerCount = mDiscoveryObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
@@ -1026,14 +1114,17 @@
public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5;
- public static final int MSG_START_PRINTER_DISCOVERY = 6;
- public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 7;
- public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 8;
- public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 9;
- public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 10;
- public static final int MSG_VALIDATE_PRINTERS = 11;
- public static final int MSG_START_PRINTER_STATE_TRACKING = 12;
- public static final int MSG_STOP_PRINTER_STATE_TRACKING = 13;
+ public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6;
+ public static final int MSG_START_PRINTER_DISCOVERY = 7;
+ public static final int MSG_STOP_PRINTER_DISCOVERY = 8;
+ public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9;
+ public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10;
+ public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11;
+ public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12;
+ public static final int MSG_VALIDATE_PRINTERS = 13;
+ public static final int MSG_START_PRINTER_STATE_TRACKING = 14;
+ public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15;
+ public static final int MSG_DESTROY_SERVICE = 16;
SessionHandler(Looper looper) {
super(looper, null, false);
@@ -1074,11 +1165,21 @@
service.createPrinterDiscoverySession();
} break;
+ case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
+ RemotePrintService service = (RemotePrintService) message.obj;
+ service.destroyPrinterDiscoverySession();
+ } break;
+
case MSG_START_PRINTER_DISCOVERY: {
RemotePrintService service = (RemotePrintService) message.obj;
service.startPrinterDiscovery(null);
} break;
+ case MSG_STOP_PRINTER_DISCOVERY: {
+ RemotePrintService service = (RemotePrintService) message.obj;
+ service.stopPrinterDiscovery();
+ } break;
+
case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
handleDispatchCreatePrinterDiscoverySession(services);
@@ -1124,7 +1225,12 @@
PrinterId printerId = (PrinterId) args.arg2;
args.recycle();
handleStopPrinterStateTracking(service, printerId);
- }
+ } break;
+
+ case MSG_DESTROY_SERVICE: {
+ RemotePrintService service = (RemotePrintService) message.obj;
+ service.destroy();
+ } break;
}
}
}
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index c215f40..46f100e 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -170,7 +170,20 @@
}
/* Client commands are forwarded to state machine */
case WifiManager.CONNECT_NETWORK:
- case WifiManager.SAVE_NETWORK:
+ case WifiManager.SAVE_NETWORK: {
+ WifiConfiguration config = (WifiConfiguration) msg.obj;
+ if (config.isValid()) {
+ mWifiStateMachine.sendMessage(Message.obtain(msg));
+ } else {
+ Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
+ if (msg.what == WifiManager.CONNECT_NETWORK) {
+ replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);
+ } else {
+ replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED);
+ }
+ }
+ break;
+ }
case WifiManager.FORGET_NETWORK:
case WifiManager.START_WPS:
case WifiManager.CANCEL_WPS:
@@ -185,6 +198,17 @@
}
}
}
+
+ private void replyFailed(Message msg, int what) {
+ Message reply = msg.obtain();
+ reply.what = what;
+ reply.arg1 = WifiManager.INVALID_ARGS;
+ try {
+ msg.replyTo.send(reply);
+ } catch (RemoteException e) {
+ // There's not much we can do if reply can't be sent!
+ }
+ }
}
private ClientHandler mClientHandler;
@@ -325,11 +349,13 @@
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 +363,10 @@
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 +389,7 @@
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 +423,18 @@
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();
}
}
@@ -547,7 +579,11 @@
*/
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
- mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
+ if (wifiConfig.isValid()) {
+ mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
+ } else {
+ Slog.e(TAG, "Invalid WifiConfiguration");
+ }
}
/**
@@ -580,7 +616,11 @@
enforceChangePermission();
if (wifiConfig == null)
return;
- mWifiStateMachine.setWifiApConfiguration(wifiConfig);
+ if (wifiConfig.isValid()) {
+ mWifiStateMachine.setWifiApConfiguration(wifiConfig);
+ } else {
+ Slog.e(TAG, "Invalid WifiConfiguration");
+ }
}
/**
@@ -638,10 +678,15 @@
*/
public int addOrUpdateNetwork(WifiConfiguration config) {
enforceChangePermission();
- if (mWifiStateMachineChannel != null) {
- return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
+ if (config.isValid()) {
+ if (mWifiStateMachineChannel != null) {
+ return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
+ } else {
+ Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+ return -1;
+ }
} else {
- Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+ Slog.e(TAG, "bad network configuration");
return -1;
}
}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
index 482dc05..f687da3 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
@@ -76,10 +76,10 @@
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 eb799ec..5bb0e77 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
@@ -47,8 +47,8 @@
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 09b495f..1f278b9 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
@@ -48,7 +48,7 @@
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 c1183987..d784f75 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeMultiple.java
@@ -57,7 +57,7 @@
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 5c0cd45..5b5eb15 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
@@ -70,9 +70,9 @@
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 334b777..0f3257b 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
@@ -57,10 +57,10 @@
}
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 d1c3358..3aadbb0 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
@@ -46,17 +46,17 @@
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 000ea9b..29fb868 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
@@ -34,8 +34,8 @@
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 70257bb..c26e93f 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/InterruptionTest.java
@@ -53,9 +53,9 @@
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 34ec6cc..92bbb85 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
@@ -54,9 +54,9 @@
// 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 @@
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 c6011f2..ecf5ef3 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
@@ -47,17 +47,17 @@
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 ab1dc26..c550e92 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
@@ -51,9 +51,9 @@
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 52c21c9..92b169e 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
@@ -52,14 +52,14 @@
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 05af044..9b246ad 100644
--- a/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
+++ b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
@@ -67,8 +67,8 @@
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/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index ea7904c..f79a4a6 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -115,6 +115,7 @@
private Context mContext;
private static final String TAG = "WifiConfigStore";
private static final boolean DBG = true;
+ private static final boolean VDBG = false;
private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf";
@@ -154,7 +155,7 @@
private static final String EOS = "eos";
private final LocalLog mLocalLog;
- WpaConfigFileObserver mFileObserver;
+ private final WpaConfigFileObserver mFileObserver;
private WifiNative mWifiNative;
private final KeyStore mKeyStore = KeyStore.getInstance();
@@ -163,10 +164,13 @@
mContext = c;
mWifiNative = wn;
- if (DBG) {
+ if (VDBG) {
mLocalLog = mWifiNative.getLocalLog();
mFileObserver = new WpaConfigFileObserver();
mFileObserver.startWatching();
+ } else {
+ mLocalLog = null;
+ mFileObserver = null;
}
}
@@ -180,7 +184,7 @@
public void onEvent(int event, String path) {
if (event == CLOSE_WRITE) {
File file = new File(SUPPLICANT_CONFIG_FILE);
- localLog("wpa_supplicant.conf changed; new size = " + file.length());
+ if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length());
}
}
}
@@ -245,7 +249,7 @@
* @return false if the network id is invalid
*/
boolean selectNetwork(int netId) {
- localLog("selectNetwork", netId);
+ if (VDBG) localLog("selectNetwork", netId);
if (netId == INVALID_NETWORK_ID) return false;
// Reset the priority of each network at start or if it goes too high.
@@ -282,7 +286,7 @@
* @return network update result
*/
NetworkUpdateResult saveNetwork(WifiConfiguration config) {
- localLog("saveNetwork", config.networkId);
+ if (VDBG) localLog("saveNetwork", config.networkId);
// A new network cannot have null SSID
if (config == null || (config.networkId == INVALID_NETWORK_ID &&
config.SSID == null)) {
@@ -331,7 +335,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean forgetNetwork(int netId) {
- localLog("forgetNetwork", netId);
+ if (VDBG) localLog("forgetNetwork", netId);
if (mWifiNative.removeNetwork(netId)) {
mWifiNative.saveConfig();
removeConfigAndSendBroadcastIfNeeded(netId);
@@ -352,7 +356,7 @@
* @return network Id
*/
int addOrUpdateNetwork(WifiConfiguration config) {
- localLog("addOrUpdateNetwork", config.networkId);
+ if (VDBG) localLog("addOrUpdateNetwork", config.networkId);
NetworkUpdateResult result = addOrUpdateNetworkNative(config);
if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
sendConfiguredNetworksChangedBroadcast(mConfiguredNetworks.get(result.getNetworkId()),
@@ -372,7 +376,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean removeNetwork(int netId) {
- localLog("removeNetwork", netId);
+ if (VDBG) localLog("removeNetwork", netId);
boolean ret = mWifiNative.removeNetwork(netId);
if (ret) {
removeConfigAndSendBroadcastIfNeeded(netId);
@@ -407,10 +411,10 @@
boolean enableNetwork(int netId, boolean disableOthers) {
boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers);
if (disableOthers) {
- localLog("enableNetwork(disableOthers=true) ", netId);
+ if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId);
sendConfiguredNetworksChangedBroadcast();
} else {
- localLog("enableNetwork(disableOthers=false) ", netId);
+ if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId);
WifiConfiguration enabledNetwork = null;
synchronized(mConfiguredNetworks) {
enabledNetwork = mConfiguredNetworks.get(netId);
@@ -437,7 +441,7 @@
}
void disableAllNetworks() {
- localLog("disableAllNetworks");
+ if (VDBG) localLog("disableAllNetworks");
boolean networkDisabled = false;
for(WifiConfiguration config : mConfiguredNetworks.values()) {
if(config != null && config.status != Status.DISABLED) {
@@ -470,7 +474,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean disableNetwork(int netId, int reason) {
- localLog("disableNetwork", netId);
+ if (VDBG) localLog("disableNetwork", netId);
boolean ret = mWifiNative.disableNetwork(netId);
WifiConfiguration network = null;
WifiConfiguration config = mConfiguredNetworks.get(netId);
@@ -683,33 +687,33 @@
if (mNetworkIds.containsKey(configKey(config))) {
// That SSID is already known, just ignore this duplicate entry
- localLog("discarded duplicate network", config.networkId);
+ if (VDBG) localLog("discarded duplicate network", config.networkId);
} else {
mConfiguredNetworks.put(config.networkId, config);
mNetworkIds.put(configKey(config), config.networkId);
- localLog("loaded configured network", config.networkId);
+ if (VDBG) localLog("loaded configured network", config.networkId);
}
}
readIpAndProxyConfigurations();
sendConfiguredNetworksChangedBroadcast();
- localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks");
+ if (VDBG) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks");
if (mNetworkIds.size() == 0) {
// no networks? Lets log if the wpa_supplicant.conf file contents
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE));
- localLog("--- Begin wpa_supplicant.conf Contents ---");
+ if (VDBG) localLog("--- Begin wpa_supplicant.conf Contents ---");
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
- localLog(line);
+ if (VDBG) localLog(line);
}
- localLog("--- End wpa_supplicant.conf Contents ---");
+ if (VDBG) localLog("--- End wpa_supplicant.conf Contents ---");
} catch (FileNotFoundException e) {
- localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e);
+ if (VDBG) localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e);
} catch (IOException e) {
- localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e);
+ if (VDBG) localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e);
} finally {
try {
if (reader != null) {
@@ -1050,7 +1054,7 @@
* refer to an existing configuration.
*/
- localLog("addOrUpdateNetworkNative " + config.getPrintableSsid());
+ if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid());
int netId = config.networkId;
boolean newNetwork = false;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index de377ee..2ce584b 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -348,6 +348,20 @@
linkProperties = new LinkProperties();
}
+ /**
+ * indicates whether the configuration is valid
+ * @return true if valid, false otherwise
+ * @hide
+ */
+ public boolean isValid() {
+ if (allowedKeyManagement.cardinality() > 1) {
+ return false;
+ }
+
+ // TODO: Add more checks
+ return true;
+ }
+
@Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2a5b4da..3223cb3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -818,6 +818,10 @@
/**
* 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) {
@@ -1366,6 +1370,13 @@
/** WPS timed out {@hide} */
public static final int WPS_TIMED_OUT = 7;
+ /**
+ * Passed with {@link ActionListener#onFailure}.
+ * Indicates that the operation failed due to invalid inputs
+ * @hide
+ */
+ public static final int INVALID_ARGS = 8;
+
/** Interface for callback invocation on an application action {@hide} */
public interface ActionListener {
/** The operation succeeded */
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 5626192..520668e 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -39,6 +39,7 @@
public class WifiNative {
private static final boolean DBG = false;
+ private static final boolean VDBG = false;
private final String mTAG;
private static final int DEFAULT_GROUP_OWNER_INTENT = 6;
@@ -117,12 +118,12 @@
public boolean connectToSupplicant() {
// No synchronization necessary .. it is implemented in WifiMonitor
- localLog(mInterfacePrefix + "connectToSupplicant");
+ if (VDBG) localLog(mInterfacePrefix + "connectToSupplicant");
return connectToSupplicantNative();
}
public void closeSupplicantConnection() {
- localLog(mInterfacePrefix + "closeSupplicantConnection");
+ if (VDBG) localLog(mInterfacePrefix + "closeSupplicantConnection");
closeSupplicantConnectionNative();
}
@@ -135,9 +136,10 @@
if (DBG) Log.d(mTAG, "doBoolean: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- localLog(cmdId + "->" + mInterfacePrefix + command);
+ if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
boolean result = doBooleanCommandNative(mInterfacePrefix + command);
- localLog(cmdId + "<-" + result);
+ if (VDBG) localLog(cmdId + "<-" + result);
+ if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
}
@@ -146,9 +148,10 @@
if (DBG) Log.d(mTAG, "doInt: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- localLog(cmdId + "->" + mInterfacePrefix + command);
+ if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
int result = doIntCommandNative(mInterfacePrefix + command);
- localLog(cmdId + "<-" + result);
+ if (VDBG) localLog(cmdId + "<-" + result);
+ if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
}
@@ -157,9 +160,10 @@
if (DBG) Log.d(mTAG, "doString: " + command);
synchronized (mLock) {
int cmdId = getNewCmdIdLocked();
- localLog(cmdId + "->" + mInterfacePrefix + command);
+ if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
String result = doStringCommandNative(mInterfacePrefix + command);
- localLog(cmdId + "<-" + result);
+ if (VDBG) localLog(cmdId + "<-" + result);
+ if (DBG) Log.d(mTAG, " returned " + result);
return result;
}
}
@@ -281,7 +285,7 @@
/**
* 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 +299,7 @@
*/
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 2bc22f2..0f1aa71 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -859,6 +859,7 @@
mExpectedBatchedScans = Integer.parseInt(scansExpected);
setNextBatchedAlarm(mExpectedBatchedScans);
} catch (NumberFormatException e) {
+ stopBatchedScan();
loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
}
}
@@ -876,6 +877,11 @@
}
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 @@
// 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 @@
// 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 @@
* 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 @@
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 @@
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 @@
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 @@
break;
case CMD_POLL_BATCHED_SCAN:
handleBatchedScanPollRequest();
+ break;
case CMD_START_NEXT_BATCHED_SCAN:
startNextBatchedScan();
break;