Merge "Set wearable specific strings in framework" into klp-modular-dev
diff --git a/api/current.txt b/api/current.txt
index 9a0c738..ee6f3f2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -32,6 +32,7 @@
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
+ field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
field public static final java.lang.String BRICK = "android.permission.BRICK";
field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
@@ -7263,6 +7264,7 @@
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
+ method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public abstract java.lang.String getNameForUid(int);
method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -10755,10 +10757,33 @@
method public int getMinDelay();
method public java.lang.String getName();
method public float getPower();
+ method public java.lang.String getRequiredPermission();
method public float getResolution();
+ method public java.lang.String getStringType();
method public int getType();
method public java.lang.String getVendor();
method public int getVersion();
+ field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+ field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+ field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
+ field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
+ field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+ field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+ field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+ field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
+ field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
+ field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+ field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+ field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+ field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+ field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+ field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+ field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+ field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+ field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+ field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+ field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
field public static final int TYPE_ACCELEROMETER = 1; // 0x1
field public static final int TYPE_ALL = -1; // 0xffffffff
field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -10767,6 +10792,7 @@
field public static final int TYPE_GRAVITY = 9; // 0x9
field public static final int TYPE_GYROSCOPE = 4; // 0x4
field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+ field public static final int TYPE_HEART_RATE = 21; // 0x15
field public static final int TYPE_LIGHT = 5; // 0x5
field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
@@ -11033,6 +11059,7 @@
public final class HdmiCecClient {
method public boolean isTvOn();
method public void sendActiveSource();
+ method public void sendGiveDevicePowerStatus(int);
method public void sendImageViewOn();
method public void sendInactiveSource();
method public void sendTextViewOn();
@@ -14388,10 +14415,13 @@
public final class NsdServiceInfo implements android.os.Parcelable {
ctor public NsdServiceInfo();
method public int describeContents();
+ method public java.util.Map<java.lang.String, byte[]> getAttributes();
method public java.net.InetAddress getHost();
method public int getPort();
method public java.lang.String getServiceName();
method public java.lang.String getServiceType();
+ method public void removeAttribute(java.lang.String);
+ method public void setAttribute(java.lang.String, java.lang.String);
method public void setHost(java.net.InetAddress);
method public void setPort(int);
method public void setServiceName(java.lang.String);
@@ -18321,7 +18351,8 @@
public final class PowerManager {
method public void goToSleep(long);
- method public boolean isScreenOn();
+ method public boolean isInteractive();
+ method public deprecated boolean isScreenOn();
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
method public void userActivity(long, boolean);
@@ -24260,6 +24291,7 @@
method public java.lang.String getInstallerPackageName(java.lang.String);
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
+ method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -26541,6 +26573,7 @@
method public float getRefreshRate();
method public int getRotation();
method public void getSize(android.graphics.Point);
+ method public int getState();
method public deprecated int getWidth();
method public boolean isValid();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
@@ -26548,6 +26581,10 @@
field public static final int FLAG_PRIVATE = 4; // 0x4
field public static final int FLAG_SECURE = 2; // 0x2
field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
+ field public static final int STATE_DOZING = 3; // 0x3
+ field public static final int STATE_OFF = 1; // 0x1
+ field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_UNKNOWN = 0; // 0x0
}
public class DragEvent implements android.os.Parcelable {
@@ -26882,7 +26919,7 @@
field public static final int FLAG_SOFT_KEYBOARD = 2; // 0x2
field public static final int FLAG_TRACKING = 512; // 0x200
field public static final int FLAG_VIRTUAL_HARD_KEY = 64; // 0x40
- field public static final int FLAG_WOKE_HERE = 1; // 0x1
+ field public static final deprecated int FLAG_WOKE_HERE = 1; // 0x1
field public static final int KEYCODE_0 = 7; // 0x7
field public static final int KEYCODE_1 = 8; // 0x8
field public static final int KEYCODE_2 = 9; // 0x9
@@ -27711,6 +27748,7 @@
method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
method public void createContextMenu(android.view.ContextMenu);
method public void destroyDrawingCache();
+ method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
method public void dispatchConfigurationChanged(android.content.res.Configuration);
method public void dispatchDisplayHint(int);
method public boolean dispatchDragEvent(android.view.DragEvent);
@@ -27742,7 +27780,7 @@
method public final android.view.View findViewById(int);
method public final android.view.View findViewWithTag(java.lang.Object);
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
- method protected boolean fitSystemWindows(android.graphics.Rect);
+ method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
method public void forceLayout();
method public static int generateViewId();
@@ -27924,6 +27962,7 @@
method public void offsetTopAndBottom(int);
method protected void onAnimationEnd();
method protected void onAnimationStart();
+ method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
method protected void onAttachedToWindow();
method public void onCancelPendingInputEvents();
method public boolean onCheckIsTextEditor();
@@ -27990,7 +28029,8 @@
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
- method public void requestFitSystemWindows();
+ method public void requestApplyInsets();
+ method public deprecated void requestFitSystemWindows();
method public final boolean requestFocus();
method public final boolean requestFocus(int);
method public boolean requestFocus(int, android.graphics.Rect);
@@ -28054,6 +28094,7 @@
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
+ method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
method public void setOnDragListener(android.view.View.OnDragListener);
@@ -28272,6 +28313,10 @@
field public static final int UNSPECIFIED = 0; // 0x0
}
+ public static abstract interface View.OnApplyWindowInsetsListener {
+ method public abstract android.view.WindowInsets onApplyWindowInsets(android.view.View, android.view.WindowInsets);
+ }
+
public static abstract interface View.OnAttachStateChangeListener {
method public abstract void onViewAttachedToWindow(android.view.View);
method public abstract void onViewDetachedFromWindow(android.view.View);
@@ -28881,6 +28926,27 @@
method public abstract void onFocusLost(android.view.WindowId);
}
+ public class WindowInsets {
+ ctor public WindowInsets(android.view.WindowInsets);
+ method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
+ method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
+ method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
+ method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
+ method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
+ method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+ method public int getSystemWindowInsetBottom();
+ method public int getSystemWindowInsetLeft();
+ method public int getSystemWindowInsetRight();
+ method public int getSystemWindowInsetTop();
+ method public int getWindowDecorInsetBottom();
+ method public int getWindowDecorInsetLeft();
+ method public int getWindowDecorInsetRight();
+ method public int getWindowDecorInsetTop();
+ method public boolean hasInsets();
+ method public boolean hasSystemWindowInsets();
+ method public boolean hasWindowDecorInsets();
+ }
+
public abstract interface WindowManager implements android.view.ViewManager {
method public abstract android.view.Display getDefaultDisplay();
method public abstract void removeViewImmediate(android.view.View);
@@ -28946,7 +29012,7 @@
field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
- field public static final int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
+ field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6f53df4..010988e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -129,6 +129,24 @@
}
@Override
+ public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+ // Try to find a main leanback_launcher activity.
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+ intentToResolve.setPackage(packageName);
+ List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
+
+ if (ris == null || ris.size() <= 0) {
+ return null;
+ }
+ Intent intent = new Intent(intentToResolve);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setClassName(ris.get(0).activityInfo.packageName,
+ ris.get(0).activityInfo.name);
+ return intent;
+ }
+
+ @Override
public int[] getPackageGids(String packageName)
throws NameNotFoundException {
try {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 590ccf89..106c1d6 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1414,15 +1414,38 @@
// Standard intent broadcast actions (see action variable).
/**
- * Broadcast Action: Sent after the screen turns off.
+ * Broadcast Action: Sent when the device goes to sleep and becomes non-interactive.
+ * <p>
+ * For historical reasons, the name of this broadcast action refers to the power
+ * state of the screen but it is actually sent in response to changes in the
+ * overall interactive state of the device.
+ * </p><p>
+ * This broadcast is sent when the device becomes non-interactive which may have
+ * nothing to do with the screen turning off. To determine the
+ * actual state of the screen, use {@link android.view.Display#getState}.
+ * </p><p>
+ * See {@link android.os.PowerManager#isInteractive} for details.
+ * </p>
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
+
/**
- * Broadcast Action: Sent after the screen turns on.
+ * Broadcast Action: Sent when the device wakes up and becomes interactive.
+ * <p>
+ * For historical reasons, the name of this broadcast action refers to the power
+ * state of the screen but it is actually sent in response to changes in the
+ * overall interactive state of the device.
+ * </p><p>
+ * This broadcast is sent when the device becomes interactive which may have
+ * nothing to do with the screen turning on. To determine the
+ * actual state of the screen, use {@link android.view.Display#getState}.
+ * </p><p>
+ * See {@link android.os.PowerManager#isInteractive} for details.
+ * </p>
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 34a6f1d..e3a0362 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -970,6 +970,7 @@
* @hide
* @deprecated
*/
+ @Deprecated
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
@@ -1266,6 +1267,7 @@
* something like a DPAD, not through touch or mouse.
* @deprecated use {@link #FEATURE_LEANBACK} instead.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_TELEVISION = "android.hardware.type.television";
@@ -1455,17 +1457,33 @@
public abstract Intent getLaunchIntentForPackage(String packageName);
/**
- * Return an array of all of the secondary group-ids that have been
- * assigned to a package.
- *
- * <p>Throws {@link NameNotFoundException} if a package with the given
- * name cannot be found on the system.
- *
+ * Return a "good" intent to launch a front-door Leanback activity in a
+ * package, for use for example to implement an "open" button when browsing
+ * through packages. The current implementation will look for a main
+ * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
+ * return null if no main leanback activities are found.
+ * <p>
+ * Throws {@link NameNotFoundException} if a package with the given name
+ * cannot be found on the system.
+ *
+ * @param packageName The name of the package to inspect.
+ * @return Returns either a fully-qualified Intent that can be used to launch
+ * the main Leanback activity in the package, or null if the package
+ * does not contain such an activity.
+ */
+ public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
+
+ /**
+ * Return an array of all of the secondary group-ids that have been assigned
+ * to a package.
+ * <p>
+ * Throws {@link NameNotFoundException} if a package with the given name
+ * cannot be found on the system.
+ *
* @param packageName The full name (i.e. com.google.apps.contacts) of the
- * desired package.
- *
- * @return Returns an int array of the assigned gids, or null if there
- * are none.
+ * desired package.
+ * @return Returns an int array of the assigned gids, or null if there are
+ * none.
*/
public abstract int[] getPackageGids(String packageName)
throws NameNotFoundException;
@@ -2449,7 +2467,7 @@
/**
* Return the generic icon for an activity that is used when no specific
* icon is defined.
- *
+ *
* @return Drawable Image of the icon.
*/
public abstract Drawable getDefaultActivityIcon();
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 89a5819..4bea9ee 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -38,6 +38,13 @@
public static final int TYPE_ACCELEROMETER = 1;
/**
+ * A constant string describing an accelerometer sensor type.
+ *
+ * @see #TYPE_ACCELEROMETER
+ */
+ public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+
+ /**
* A constant describing a magnetic field sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -45,6 +52,13 @@
public static final int TYPE_MAGNETIC_FIELD = 2;
/**
+ * A constant string describing a magnetic field sensor type.
+ *
+ * @see #TYPE_MAGNETIC_FIELD
+ */
+ public static final String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+
+ /**
* A constant describing an orientation sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -55,24 +69,58 @@
@Deprecated
public static final int TYPE_ORIENTATION = 3;
- /** A constant describing a gyroscope sensor type.
+ /**
+ * A constant string describing an orientation sensor type.
+ *
+ * @see #TYPE_ORIENTATION
+ * @deprecated use {@link android.hardware.SensorManager#getOrientation
+ * SensorManager.getOrientation()} instead.
+ */
+ @Deprecated
+ public static final String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+
+ /**
+ * A constant describing a gyroscope sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details. */
public static final int TYPE_GYROSCOPE = 4;
/**
+ * A constant string describing a gyroscope sensor type.
+ *
+ * @see #TYPE_GYROSCOPE
+ */
+ public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+
+ /**
* A constant describing a light sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
*/
public static final int TYPE_LIGHT = 5;
- /** A constant describing a pressure sensor type.
+ /**
+ * A constant string describing a light sensor type.
+ *
+ * @see #TYPE_LIGHT
+ */
+ public static final String STRING_TYPE_LIGHT = "android.sensor.light";
+
+ /**
+ * A constant describing a pressure sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
- * for more details. */
+ * for more details.
+ */
public static final int TYPE_PRESSURE = 6;
/**
+ * A constant string describing a pressure sensor type.
+ *
+ * @see #TYPE_PRESSURE
+ */
+ public static final String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+
+ /**
* A constant describing a temperature sensor type
*
* @deprecated use
@@ -83,6 +131,17 @@
public static final int TYPE_TEMPERATURE = 7;
/**
+ * A constant string describing a temperature sensor type
+ *
+ * @see #TYPE_TEMPERATURE
+ * @deprecated use
+ * {@link android.hardware.Sensor#STRING_TYPE_AMBIENT_TEMPERATURE
+ * Sensor.STRING_TYPE_AMBIENT_TEMPERATURE} instead.
+ */
+ @Deprecated
+ public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+
+ /**
* A constant describing a proximity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -90,6 +149,13 @@
public static final int TYPE_PROXIMITY = 8;
/**
+ * A constant string describing a proximity sensor type.
+ *
+ * @see #TYPE_PROXIMITY
+ */
+ public static final String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+
+ /**
* A constant describing a gravity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -97,6 +163,13 @@
public static final int TYPE_GRAVITY = 9;
/**
+ * A constant string describing a gravity sensor type.
+ *
+ * @see #TYPE_GRAVITY
+ */
+ public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+
+ /**
* A constant describing a linear acceleration sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -104,6 +177,14 @@
public static final int TYPE_LINEAR_ACCELERATION = 10;
/**
+ * A constant string describing a linear acceleration sensor type.
+ *
+ * @see #TYPE_LINEAR_ACCELERATION
+ */
+ public static final String STRING_TYPE_LINEAR_ACCELERATION =
+ "android.sensor.linear_acceleration";
+
+ /**
* A constant describing a rotation vector sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -111,18 +192,42 @@
public static final int TYPE_ROTATION_VECTOR = 11;
/**
+ * A constant string describing a rotation vector sensor type.
+ *
+ * @see #TYPE_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+
+ /**
* A constant describing a relative humidity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
*/
public static final int TYPE_RELATIVE_HUMIDITY = 12;
- /** A constant describing an ambient temperature sensor type.
+ /**
+ * A constant string describing a relative humidity sensor type
+ *
+ * @see #TYPE_RELATIVE_HUMIDITY
+ */
+ public static final String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+
+ /**
+ * A constant describing an ambient temperature sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
- * for more details. */
+ * for more details.
+ */
public static final int TYPE_AMBIENT_TEMPERATURE = 13;
/**
+ * A constant string describing an ambient temperature sensor type.
+ *
+ * @see #TYPE_AMBIENT_TEMPERATURE
+ */
+ public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
+ "android.sensor.ambient_temperature";
+
+ /**
* A constant describing an uncalibrated magnetic field sensor type.
* <p>
* Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (device calibration
@@ -139,6 +244,13 @@
* details.
*/
public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
+ /**
+ * A constant string describing an uncalibrated magnetic field sensor type.
+ *
+ * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
+ */
+ public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
+ "android.sensor.magnetic_field_uncalibrated";
/**
* A constant describing an uncalibrated rotation vector sensor type.
@@ -156,10 +268,17 @@
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more
* details.
*/
-
public static final int TYPE_GAME_ROTATION_VECTOR = 15;
/**
+ * A constant string describing an uncalibrated rotation vector sensor type.
+ *
+ * @see #TYPE_GAME_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
+ "android.sensor.game_rotation_vector";
+
+ /**
* A constant describing an uncalibrated gyroscope sensor type.
* <p>Similar to {@link #TYPE_GYROSCOPE} but no gyro-drift compensation has been performed
* to adjust the given sensor values. However, such gyro-drift bias values
@@ -174,6 +293,14 @@
public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
/**
+ * A constant string describing an uncalibrated gyroscope sensor type.
+ *
+ * @see #TYPE_GYROSCOPE_UNCALIBRATED
+ */
+ public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
+ "android.sensor.gyroscope_uncalibrated";
+
+ /**
* A constant describing a significant motion trigger sensor.
* <p>
* It triggers when an event occurs and then automatically disables
@@ -186,6 +313,14 @@
public static final int TYPE_SIGNIFICANT_MOTION = 17;
/**
+ * A constant string describing a significant motion trigger sensor.
+ *
+ * @see #TYPE_SIGNIFICANT_MOTION
+ */
+ public static final String STRING_TYPE_SIGNIFICANT_MOTION =
+ "android.sensor.significant_motion";
+
+ /**
* A constant describing a step detector sensor.
* <p>
* A sensor of this type triggers an event each time a step is taken by the user. The only
@@ -198,6 +333,13 @@
public static final int TYPE_STEP_DETECTOR = 18;
/**
+ * A constant string describing a step detector sensor.
+ *
+ * @see #TYPE_STEP_DETECTOR
+ */
+ public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+
+ /**
* A constant describing a step counter sensor.
* <p>
* A sensor of this type returns the number of steps taken by the user since the last reboot
@@ -211,7 +353,14 @@
public static final int TYPE_STEP_COUNTER = 19;
/**
- * A constant describing the geo-magnetic rotation vector.
+ * A constant string describing a step counter sensor.
+ *
+ * @see #TYPE_STEP_COUNTER
+ */
+ public static final String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+
+ /**
+ * A constant describing a geo-magnetic rotation vector.
* <p>
* Similar to {@link #TYPE_ROTATION_VECTOR}, but using a magnetometer instead of using a
* gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
@@ -222,6 +371,32 @@
public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
/**
+ * A constant string describing a geo-magnetic rotation vector.
+ *
+ * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
+ "android.sensor.geomagnetic_rotation_vector";
+
+ /**
+ * A constant describing a heart rate monitor.
+ * <p>
+ * A sensor that measures the heart rate in beats per minute.
+ * <p>
+ * value[0] represents the beats per minute when the measurement was taken.
+ * value[0] is 0 if the heart rate monitor could not measure the rate or the
+ * rate is 0 beat per minute.
+ */
+ public static final int TYPE_HEART_RATE = 21;
+
+ /**
+ * A constant string describing a heart rate monitor.
+ *
+ * @see #TYPE_HEART_RATE
+ */
+ public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+
+ /**
* A constant describing all sensor types.
*/
public static final int TYPE_ALL = -1;
@@ -265,7 +440,8 @@
// added post 4.3
REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_DETECTOR
REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_COUNTER
- REPORTING_MODE_CONTINUOUS, 5 // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ REPORTING_MODE_ON_CHANGE, 1 // SENSOR_TYPE_HEART_RATE_MONITOR
};
static int getReportingMode(Sensor sensor) {
@@ -321,6 +497,8 @@
private int mMinDelay;
private int mFifoReservedEventCount;
private int mFifoMaxEventCount;
+ private String mStringType;
+ private String mRequiredPermission;
Sensor() {
}
@@ -401,6 +579,20 @@
return mFifoMaxEventCount;
}
+ /**
+ * @return The type of this sensor as a string.
+ */
+ public String getStringType() {
+ return mStringType;
+ }
+
+ /**
+ * @return The permission required to access this sensor. If empty, no permission is required.
+ */
+ public String getRequiredPermission() {
+ return mRequiredPermission;
+ }
+
/** @hide */
public int getHandle() {
return mHandle;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 03fa1d5..cec90cd 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -58,16 +58,6 @@
public abstract boolean isProximitySensorAvailable();
/**
- * Called by the power manager to blank all displays.
- */
- public abstract void blankAllDisplaysFromPowerManager();
-
- /**
- * Called by the power manager to unblank all displays.
- */
- public abstract void unblankAllDisplaysFromPowerManager();
-
- /**
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
@@ -254,12 +244,10 @@
void onStateChanged();
void onProximityPositive();
void onProximityNegative();
+ void onDisplayStateChange(int state); // one of the Display state constants
void acquireSuspendBlocker();
void releaseSuspendBlocker();
-
- void blankAllDisplays();
- void unblankAllDisplays();
}
/**
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
index 1f382e6..cd86cd8 100644
--- a/core/java/android/hardware/hdmi/HdmiCecClient.java
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -88,7 +88,7 @@
}
/**
- * Send <TextViewOn> message.
+ * Send <Text View On> message.
*/
public void sendTextViewOn() {
try {
@@ -99,7 +99,7 @@
}
/**
- * Send <ImageViewOn> message.
+ * Send <Image View On> message.
*/
public void sendImageViewOn() {
try {
@@ -110,6 +110,20 @@
}
/**
+ * Send <Give Device Power Status> message.
+ *
+ * @param address logical address of the device to send the message to, such as
+ * {@link HdmiCec#ADDR_TV}.
+ */
+ public void sendGiveDevicePowerStatus(int address) {
+ try {
+ mService.sendGiveDevicePowerStatus(mBinder, address);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+ }
+ }
+
+ /**
* Returns true if the TV or attached display is powered on.
* <p>
* The result of this method is only meaningful on playback devices (where the device
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
index b5df131..ecdd345 100644
--- a/core/java/android/hardware/hdmi/IHdmiCecService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -33,6 +33,7 @@
void sendInactiveSource(IBinder b);
void sendImageViewOn(IBinder b);
void sendTextViewOn(IBinder b);
+ void sendGiveDevicePowerStatus(IBinder b, int address);
boolean isTvOn(IBinder b);
void sendMessage(IBinder b, in HdmiCecMessage message);
}
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 8be94d0..6a392dd 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -25,12 +25,18 @@
* @hide Only for use within the system server.
*/
public abstract class InputManagerInternal {
+ public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+
/**
- * Sets information about the displays as needed by the input system.
- * The input system should copy this information if required.
+ * Called by the display manager to set information about the displays as needed
+ * by the input system. The input system must copy this information to retain it.
*/
public abstract void setDisplayViewports(DisplayViewport defaultViewport,
DisplayViewport externalTouchViewport);
- public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+ /**
+ * Called by the power manager to tell the input manager whether it should start
+ * watching for wake events.
+ */
+ public abstract void setInteractive(boolean interactive);
}
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 205a21d..6fdb0d0 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -18,8 +18,15 @@
import android.os.Parcelable;
import android.os.Parcel;
+import android.util.Log;
+import android.util.ArrayMap;
+import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
+
/**
* A class representing service information for network service discovery
@@ -27,11 +34,13 @@
*/
public final class NsdServiceInfo implements Parcelable {
+ private static final String TAG = "NsdServiceInfo";
+
private String mServiceName;
private String mServiceType;
- private DnsSdTxtRecord mTxtRecord;
+ private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<String, byte[]>();
private InetAddress mHost;
@@ -41,10 +50,9 @@
}
/** @hide */
- public NsdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) {
+ public NsdServiceInfo(String sn, String rt) {
mServiceName = sn;
mServiceType = rt;
- mTxtRecord = tr;
}
/** Get the service name */
@@ -67,16 +75,6 @@
mServiceType = s;
}
- /** @hide */
- public DnsSdTxtRecord getTxtRecord() {
- return mTxtRecord;
- }
-
- /** @hide */
- public void setTxtRecord(DnsSdTxtRecord t) {
- mTxtRecord = new DnsSdTxtRecord(t);
- }
-
/** Get the host address. The host address is valid for a resolved service. */
public InetAddress getHost() {
return mHost;
@@ -97,14 +95,134 @@
mPort = p;
}
+ /** @hide */
+ public void setAttribute(String key, byte[] value) {
+ // Key must be printable US-ASCII, excluding =.
+ for (int i = 0; i < key.length(); ++i) {
+ char character = key.charAt(i);
+ if (character < 0x20 || character > 0x7E) {
+ throw new IllegalArgumentException("Key strings must be printable US-ASCII");
+ } else if (character == 0x3D) {
+ throw new IllegalArgumentException("Key strings must not include '='");
+ }
+ }
+
+ // Key length + value length must be < 255.
+ if (key.length() + (value == null ? 0 : value.length) >= 255) {
+ throw new IllegalArgumentException("Key length + value length must be < 255 bytes");
+ }
+
+ // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4.
+ if (key.length() > 9) {
+ Log.w(TAG, "Key lengths > 9 are discouraged: " + key);
+ }
+
+ // Check against total TXT record size limits.
+ // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2.
+ int txtRecordSize = getTxtRecordSize();
+ int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2;
+ if (futureSize > 1300) {
+ throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes");
+ } else if (futureSize > 400) {
+ Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur");
+ }
+
+ mTxtRecord.put(key, value);
+ }
+
+ /**
+ * Add a service attribute as a key/value pair.
+ *
+ * <p> Service attributes are included as DNS-SD TXT record pairs.
+ *
+ * <p> The key must be US-ASCII printable characters, excluding the '=' character. Values may
+ * be UTF-8 strings or null. The total length of key + value must be less than 255 bytes.
+ *
+ * <p> Keys should be short, ideally no more than 9 characters, and unique per instance of
+ * {@link NsdServiceInfo}. Calling {@link #setAttribute} twice with the same key will overwrite
+ * first value.
+ */
+ public void setAttribute(String key, String value) {
+ try {
+ setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalArgumentException("Value must be UTF-8");
+ }
+ }
+
+ /** Remove an attribute by key */
+ public void removeAttribute(String key) {
+ mTxtRecord.remove(key);
+ }
+
+ /**
+ * Retrive attributes as a map of String keys to byte[] values.
+ *
+ * <p> The returned map is unmodifiable; changes must be made through {@link #setAttribute} and
+ * {@link #removeAttribute}.
+ */
+ public Map<String, byte[]> getAttributes() {
+ return Collections.unmodifiableMap(mTxtRecord);
+ }
+
+ private int getTxtRecordSize() {
+ int txtRecordSize = 0;
+ for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+ txtRecordSize += 2; // One for the length byte, one for the = between key and value.
+ txtRecordSize += entry.getKey().length();
+ byte[] value = entry.getValue();
+ txtRecordSize += value == null ? 0 : value.length;
+ }
+ return txtRecordSize;
+ }
+
+ /** @hide */
+ public byte[] getTxtRecord() {
+ int txtRecordSize = getTxtRecordSize();
+ if (txtRecordSize == 0) {
+ return null;
+ }
+
+ byte[] txtRecord = new byte[txtRecordSize];
+ int ptr = 0;
+ for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+ String key = entry.getKey();
+ byte[] value = entry.getValue();
+
+ // One byte to record the length of this key/value pair.
+ txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1);
+
+ // The key, in US-ASCII.
+ // Note: use the StandardCharsets const here because it doesn't raise exceptions and we
+ // already know the key is ASCII at this point.
+ System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr,
+ key.length());
+ ptr += key.length();
+
+ // US-ASCII '=' character.
+ txtRecord[ptr++] = (byte)'=';
+
+ // The value, as any raw bytes.
+ if (value != null) {
+ System.arraycopy(value, 0, txtRecord, ptr, value.length);
+ ptr += value.length;
+ }
+ }
+ return txtRecord;
+ }
+
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("name: ").append(mServiceName).
- append("type: ").append(mServiceType).
- append("host: ").append(mHost).
- append("port: ").append(mPort).
- append("txtRecord: ").append(mTxtRecord);
+ sb.append("name: ").append(mServiceName)
+ .append(", type: ").append(mServiceType)
+ .append(", host: ").append(mHost)
+ .append(", port: ").append(mPort);
+
+ byte[] txtRecord = getTxtRecord();
+ if (txtRecord != null) {
+ sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
+ }
return sb.toString();
}
@@ -117,14 +235,27 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mServiceName);
dest.writeString(mServiceType);
- dest.writeParcelable(mTxtRecord, flags);
if (mHost != null) {
- dest.writeByte((byte)1);
+ dest.writeInt(1);
dest.writeByteArray(mHost.getAddress());
} else {
- dest.writeByte((byte)0);
+ dest.writeInt(0);
}
dest.writeInt(mPort);
+
+ // TXT record key/value pairs.
+ dest.writeInt(mTxtRecord.size());
+ for (String key : mTxtRecord.keySet()) {
+ byte[] value = mTxtRecord.get(key);
+ if (value != null) {
+ dest.writeInt(1);
+ dest.writeInt(value.length);
+ dest.writeByteArray(value);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeString(key);
+ }
}
/** Implement the Parcelable interface */
@@ -134,15 +265,26 @@
NsdServiceInfo info = new NsdServiceInfo();
info.mServiceName = in.readString();
info.mServiceType = in.readString();
- info.mTxtRecord = in.readParcelable(null);
- if (in.readByte() == 1) {
+ if (in.readInt() == 1) {
try {
info.mHost = InetAddress.getByAddress(in.createByteArray());
} catch (java.net.UnknownHostException e) {}
}
info.mPort = in.readInt();
+
+ // TXT record key/value pairs.
+ int recordCount = in.readInt();
+ for (int i = 0; i < recordCount; ++i) {
+ byte[] valueArray = null;
+ if (in.readInt() == 1) {
+ int valueLength = in.readInt();
+ valueArray = new byte[valueLength];
+ in.readByteArray(valueArray);
+ }
+ info.mTxtRecord.put(in.readString(), valueArray);
+ }
return info;
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 56176a4..92af1a5 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -37,8 +37,8 @@
void wakeUp(long time);
void goToSleep(long time, int reason);
void nap(long time);
+ boolean isInteractive();
- boolean isScreenOn();
void reboot(boolean confirm, String reason, boolean wait);
void shutdown(boolean confirm, boolean wait);
void crash(String message);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 86ef479..646bfef 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -582,21 +582,64 @@
}
/**
- * Returns whether the screen is currently on.
+ * Returns true if the device is in an interactive state.
* <p>
- * Only indicates whether the screen is on. The screen could be either bright or dim.
+ * For historical reasons, the name of this method refers to the power state of
+ * the screen but it actually describes the overall interactive state of
+ * the device. This method has been replaced by {@link #isInteractive}.
* </p><p>
- * {@samplecode
- * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- * boolean isScreenOn = pm.isScreenOn();
- * }
+ * The value returned by this method only indicates whether the device is
+ * in an interactive state which may have nothing to do with the screen being
+ * on or off. To determine the actual state of the screen,
+ * use {@link android.view.Display#getState}.
* </p>
*
- * @return whether the screen is on (bright or dim).
+ * @return True if the device is in an interactive state.
+ *
+ * @deprecated Use {@link #isInteractive} instead.
*/
+ @Deprecated
public boolean isScreenOn() {
+ return isInteractive();
+ }
+
+ /**
+ * Returns true if the device is in an interactive state.
+ * <p>
+ * When this method returns true, the device is awake and ready to interact
+ * with the user (although this is not a guarantee that the user is actively
+ * interacting with the device just this moment). The main screen is usually
+ * turned on while in this state. Certain features, such as the proximity
+ * sensor, may temporarily turn off the screen while still leaving the device in an
+ * interactive state. Note in particular that the device is still considered
+ * to be interactive while dreaming (since dreams can be interactive) but not
+ * when it is dozing or asleep.
+ * </p><p>
+ * When this method returns false, the device is dozing or asleep and must
+ * be awoken before it will become ready to interact with the user again. The
+ * main screen is usually turned off while in this state. Certain features,
+ * such as "ambient mode" may cause the main screen to remain on (albeit in a
+ * low power state) to display system-provided content while the device dozes.
+ * </p><p>
+ * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on}
+ * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast
+ * whenever the interactive state of the device changes. For historical reasons,
+ * the names of these broadcasts refer to the power state of the screen
+ * but they are actually sent in response to changes in the overall interactive
+ * state of the device, as described by this method.
+ * </p><p>
+ * Services may use the non-interactive state as a hint to conserve power
+ * since the user is not present.
+ * </p>
+ *
+ * @return True if the device is in an interactive state.
+ *
+ * @see android.content.Intent#ACTION_SCREEN_ON
+ * @see android.content.Intent#ACTION_SCREEN_OFF
+ */
+ public boolean isInteractive() {
try {
- return mService.isScreenOn();
+ return mService.isInteractive();
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index de9eeff..2303d65 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -789,10 +789,20 @@
return;
}
- // start it up
- if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
- mStarted = true;
- onDreamingStarted();
+ // We need to defer calling onDreamingStarted until after onWindowAttached,
+ // which is posted to the handler by addView, so we post onDreamingStarted
+ // to the handler also. Need to watch out here in case detach occurs before
+ // this callback is invoked.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mWindow != null) {
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ mStarted = true;
+ onDreamingStarted();
+ }
+ }
+ });
}
private void safelyFinish() {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 7d310a2..c4494f4 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -204,6 +204,36 @@
public static final int TYPE_VIRTUAL = 5;
/**
+ * Display state: The display state is unknown.
+ *
+ * @see #getState
+ */
+ public static final int STATE_UNKNOWN = 0;
+
+ /**
+ * Display state: The display is off.
+ *
+ * @see #getState
+ */
+ public static final int STATE_OFF = 1;
+
+ /**
+ * Display state: The display is on.
+ *
+ * @see #getState
+ */
+ public static final int STATE_ON = 2;
+
+ /**
+ * Display state: The display is dozing in a low-power state; it may be showing
+ * system-provided content while the device is in a non-interactive state.
+ *
+ * @see #getState
+ * @see android.os.PowerManager#isInteractive
+ */
+ public static final int STATE_DOZING = 3;
+
+ /**
* Internal method to create a display.
* Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
* or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -628,6 +658,19 @@
}
/**
+ * Gets the state of the display, such as whether it is on or off.
+ *
+ * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
+ * {@link #STATE_DOZING}, or {@link #STATE_UNKNOWN}.
+ */
+ public int getState() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN;
+ }
+ }
+
+ /**
* Returns true if the specified UID has access to this display.
* @hide
*/
@@ -718,5 +761,22 @@
return Integer.toString(type);
}
}
-}
+ /**
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_UNKNOWN:
+ return "UNKNOWN";
+ case STATE_OFF:
+ return "OFF";
+ case STATE_ON:
+ return "ON";
+ case STATE_DOZING:
+ return "DOZING";
+ default:
+ return Integer.toString(state);
+ }
+ }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 8944207..5f840d3 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,11 @@
public float physicalYDpi;
/**
+ * The state of the display, such as {@link android.view.Display#STATE_ON}.
+ */
+ public int state;
+
+ /**
* The UID of the application that owns this display, or zero if it is owned by the system.
* <p>
* If the display is private, then only the owner can use it.
@@ -248,6 +253,7 @@
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
+ && state == other.state
&& ownerUid == other.ownerUid
&& Objects.equal(ownerPackageName, other.ownerPackageName);
}
@@ -280,6 +286,7 @@
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
+ state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
}
@@ -307,6 +314,7 @@
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
+ state = source.readInt();
ownerUid = source.readInt();
ownerPackageName = source.readString();
}
@@ -335,6 +343,7 @@
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
+ dest.writeInt(state);
dest.writeInt(ownerUid);
dest.writeString(ownerPackageName);
}
@@ -431,7 +440,7 @@
sb.append(smallestNominalAppHeight);
sb.append(", ");
sb.append(refreshRate);
- sb.append(" fps, rotation");
+ sb.append(" fps, rotation ");
sb.append(rotation);
sb.append(", density ");
sb.append(logicalDensityDpi);
@@ -446,6 +455,8 @@
if (address != null) {
sb.append(", address ").append(address);
}
+ sb.append(", state ");
+ sb.append(Display.stateToString(state));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8ec07ef..3670eed 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -50,7 +50,6 @@
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
- void dispatchScreenState(boolean on);
/**
* Tell the window that it is either gaining or losing focus. Keep it up
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 437ccfb..7b389c0 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1167,9 +1167,13 @@
/**
* This mask is set if the device woke because of this key event.
+ *
+ * @deprecated This flag will never be set by the system since the system
+ * consumes all wake keys itself.
*/
+ @Deprecated
public static final int FLAG_WOKE_HERE = 0x1;
-
+
/**
* This mask is set if the key event was generated by a software keyboard.
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 80725dc..e6debc1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2269,6 +2269,16 @@
static final int PFLAG3_CALLED_SUPER = 0x10;
+ /**
+ * Flag indicating that we're in the process of applying window insets.
+ */
+ static final int PFLAG3_APPLYING_INSETS = 0x40;
+
+ /**
+ * Flag indicating that we're in the process of fitting system windows using the old method.
+ */
+ static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
+
/* End of masks for mPrivateFlags3 */
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
@@ -3178,6 +3188,8 @@
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+
+ OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
}
ListenerInfo mListenerInfo;
@@ -5903,8 +5915,31 @@
* @see #getFitsSystemWindows()
* @see #setFitsSystemWindows(boolean)
* @see #setSystemUiVisibility(int)
+ *
+ * @deprecated As of API XX use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
+ * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use
+ * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)}
+ * to implement handling their own insets.
*/
protected boolean fitSystemWindows(Rect insets) {
+ if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
+ // If we're not in the process of dispatching the newer apply insets call,
+ // that means we're not in the compatibility path. Dispatch into the newer
+ // apply insets path and take things from there.
+ try {
+ mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
+ return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+ } finally {
+ mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
+ }
+ } else {
+ // We're being called from the newer apply insets path.
+ // Perform the standard fallback behavior.
+ return fitSystemWindowsInt(insets);
+ }
+ }
+
+ private boolean fitSystemWindowsInt(Rect insets) {
if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
@@ -5924,6 +5959,97 @@
}
/**
+ * Called when the view should apply {@link WindowInsets} according to its internal policy.
+ *
+ * <p>This method should be overridden by views that wish to apply a policy different from or
+ * in addition to the default behavior. Clients that wish to force a view subtree
+ * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p>
+ *
+ * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set
+ * it will be called during dispatch instead of this method. The listener may optionally
+ * call this method from its own implementation if it wishes to apply the view's default
+ * insets policy in addition to its own.</p>
+ *
+ * <p>Implementations of this method should either return the insets parameter unchanged
+ * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed
+ * that this view applied itself. This allows new inset types added in future platform
+ * versions to pass through existing implementations unchanged without being erroneously
+ * consumed.</p>
+ *
+ * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows}
+ * property is set then the view will consume the system window insets and apply them
+ * as padding for the view.</p>
+ *
+ * @param insets Insets to apply
+ * @return The supplied insets with any applied insets consumed
+ */
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
+ // We weren't called from within a direct call to fitSystemWindows,
+ // call into it as a fallback in case we're in a class that overrides it
+ // and has logic to perform.
+ if (fitSystemWindows(insets.getSystemWindowInsets())) {
+ return insets.cloneWithSystemWindowInsetsConsumed();
+ }
+ } else {
+ // We were called from within a direct call to fitSystemWindows.
+ if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+ return insets.cloneWithSystemWindowInsetsConsumed();
+ }
+ }
+ return insets;
+ }
+
+ /**
+ * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
+ * window insets to this view. The listener's
+ * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+ * method will be called instead of the view's
+ * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+ *
+ * @param listener Listener to set
+ *
+ * @see #onApplyWindowInsets(WindowInsets)
+ */
+ public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) {
+ getListenerInfo().mOnApplyWindowInsetsListener = listener;
+ }
+
+ /**
+ * Request to apply the given window insets to this view or another view in its subtree.
+ *
+ * <p>This method should be called by clients wishing to apply insets corresponding to areas
+ * obscured by window decorations or overlays. This can include the status and navigation bars,
+ * action bars, input methods and more. New inset categories may be added in the future.
+ * The method returns the insets provided minus any that were applied by this view or its
+ * children.</p>
+ *
+ * <p>Clients wishing to provide custom behavior should override the
+ * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a
+ * {@link OnApplyWindowInsetsListener} via the
+ * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener}
+ * method.</p>
+ *
+ * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method.
+ * </p>
+ *
+ * @param insets Insets to apply
+ * @return The provided insets minus the insets that were consumed
+ */
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ try {
+ mPrivateFlags3 |= PFLAG3_APPLYING_INSETS;
+ if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+ return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets);
+ } else {
+ return onApplyWindowInsets(insets);
+ }
+ } finally {
+ mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS;
+ }
+ }
+
+ /**
* @hide Compute the insets that should be consumed by this view and the ones
* that should propagate to those under it.
*/
@@ -5995,6 +6121,7 @@
/**
* Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed.
+ * @deprecated Use {@link #requestApplyInsets()} for newer platform versions.
*/
public void requestFitSystemWindows() {
if (mParent != null) {
@@ -6003,6 +6130,13 @@
}
/**
+ * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed.
+ */
+ public void requestApplyInsets() {
+ requestFitSystemWindows();
+ }
+
+ /**
* For use by PhoneWindow to make its own system window fitting optional.
* @hide
*/
@@ -16840,8 +16974,8 @@
// If the screen is off assume the animation start time is now instead of
// the next frame we draw. Keeping the START_ON_FIRST_FRAME start time
// would cause the animation to start when the screen turns back on
- if (mAttachInfo != null && !mAttachInfo.mScreenOn &&
- animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
+ if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF
+ && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());
}
animation.reset();
@@ -18668,6 +18802,31 @@
public void onViewDetachedFromWindow(View v);
}
+ /**
+ * Listener for applying window insets on a view in a custom way.
+ *
+ * <p>Apps may choose to implement this interface if they want to apply custom policy
+ * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener
+ * is set, its
+ * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+ * method will be called instead of the View's own
+ * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener
+ * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply
+ * the View's normal behavior as part of its own.</p>
+ */
+ public interface OnApplyWindowInsetsListener {
+ /**
+ * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set}
+ * on a View, this listener method will be called instead of the view's own
+ * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+ *
+ * @param v The view applying window insets
+ * @param insets The insets to apply
+ * @return The insets supplied, minus any insets that were consumed
+ */
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
+ }
+
private final class UnsetPressedState implements Runnable {
public void run() {
setPressed(false);
@@ -18713,7 +18872,7 @@
* A set of information given to a view when it is attached to its parent
* window.
*/
- static class AttachInfo {
+ final static class AttachInfo {
interface Callbacks {
void playSoundEffect(int effectId);
boolean performHapticFeedback(int effectId, boolean always);
@@ -18779,7 +18938,14 @@
boolean mHardwareAccelerationRequested;
HardwareRenderer mHardwareRenderer;
- boolean mScreenOn;
+ /**
+ * The state of the display to which the window is attached, as reported
+ * by {@link Display#getState()}. Note that the display state constants
+ * declared by {@link Display} do not exactly line up with the screen state
+ * constants declared by {@link View} (there are more display states than
+ * screen states).
+ */
+ int mDisplayState = Display.STATE_UNKNOWN;
/**
* Scale factor used by the compatibility mode
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5763e72..f346ee8 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5429,21 +5429,19 @@
}
}
-
@Override
- protected boolean fitSystemWindows(Rect insets) {
- boolean done = super.fitSystemWindows(insets);
- if (!done) {
- final int count = mChildrenCount;
- final View[] children = mChildren;
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ insets = super.dispatchApplyWindowInsets(insets);
+ if (insets.hasInsets()) {
+ final int count = getChildCount();
for (int i = 0; i < count; i++) {
- done = children[i].fitSystemWindows(insets);
- if (done) {
+ insets = getChildAt(i).dispatchApplyWindowInsets(insets);
+ if (!insets.hasInsets()) {
break;
}
}
}
- return done;
+ return insets;
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1848a8f97..521cfbfa 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -36,6 +36,8 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Bundle;
@@ -134,6 +136,7 @@
final Context mContext;
final IWindowSession mWindowSession;
final Display mDisplay;
+ final DisplayManager mDisplayManager;
final String mBasePackageName;
final int[] mTmpLocation = new int[2];
@@ -368,9 +371,7 @@
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
-
- PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mAttachInfo.mScreenOn = powerManager.isScreenOn();
+ mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
loadSystemProperties();
}
@@ -425,6 +426,10 @@
synchronized (this) {
if (mView == null) {
mView = view;
+
+ mAttachInfo.mDisplayState = mDisplay.getState();
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
@@ -794,18 +799,43 @@
scheduleTraversals();
}
- void handleScreenStateChange(boolean on) {
- if (on != mAttachInfo.mScreenOn) {
- mAttachInfo.mScreenOn = on;
- if (mView != null) {
- mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
- }
- if (on) {
- mFullRedrawNeeded = true;
- scheduleTraversals();
+ private final DisplayListener mDisplayListener = new DisplayListener() {
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (mView != null && mDisplay.getDisplayId() == displayId) {
+ final int oldDisplayState = mAttachInfo.mDisplayState;
+ final int newDisplayState = mDisplay.getState();
+ if (oldDisplayState != newDisplayState) {
+ mAttachInfo.mDisplayState = newDisplayState;
+ if (oldDisplayState != Display.STATE_UNKNOWN) {
+ final int oldScreenState = toViewScreenState(oldDisplayState);
+ final int newScreenState = toViewScreenState(newDisplayState);
+ if (oldScreenState != newScreenState) {
+ mView.dispatchScreenStateChanged(newScreenState);
+ }
+ if (oldDisplayState == Display.STATE_OFF) {
+ // Draw was suppressed so we need to for it to happen here.
+ mFullRedrawNeeded = true;
+ scheduleTraversals();
+ }
+ }
+ }
}
}
- }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ }
+
+ private int toViewScreenState(int displayState) {
+ return displayState == Display.STATE_OFF ?
+ View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
+ }
+ };
@Override
public void requestFitSystemWindows() {
@@ -2236,7 +2266,7 @@
}
private void performDraw() {
- if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
+ if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
}
@@ -2872,6 +2902,8 @@
mInputChannel = null;
}
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
+
unscheduleTraversals();
}
@@ -2951,7 +2983,6 @@
private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
private final static int MSG_UPDATE_CONFIGURATION = 18;
private final static int MSG_PROCESS_INPUT_EVENTS = 19;
- private final static int MSG_DISPATCH_SCREEN_STATE = 20;
private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
private final static int MSG_INVALIDATE_WORLD = 23;
@@ -2998,8 +3029,6 @@
return "MSG_UPDATE_CONFIGURATION";
case MSG_PROCESS_INPUT_EVENTS:
return "MSG_PROCESS_INPUT_EVENTS";
- case MSG_DISPATCH_SCREEN_STATE:
- return "MSG_DISPATCH_SCREEN_STATE";
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
case MSG_DISPATCH_DONE_ANIMATING:
@@ -3215,11 +3244,6 @@
}
updateConfiguration(config, false);
} break;
- case MSG_DISPATCH_SCREEN_STATE: {
- if (mView != null) {
- handleScreenStateChange(msg.arg1 == 1);
- }
- } break;
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
setAccessibilityFocus(null, null);
} break;
@@ -5805,12 +5829,6 @@
mHandler.sendMessage(msg);
}
- public void dispatchScreenStateChange(boolean on) {
- Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
- msg.arg1 = on ? 1 : 0;
- mHandler.sendMessage(msg);
- }
-
public void dispatchGetNewSurface() {
Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
mHandler.sendMessage(msg);
@@ -6149,14 +6167,6 @@
}
@Override
- public void dispatchScreenState(boolean on) {
- final ViewRootImpl viewAncestor = mViewAncestor.get();
- if (viewAncestor != null) {
- viewAncestor.dispatchScreenStateChange(on);
- }
- }
-
- @Override
public void dispatchGetNewSurface() {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
new file mode 100644
index 0000000..cdfcb43
--- /dev/null
+++ b/core/java/android/view/WindowInsets.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.view;
+
+import android.graphics.Rect;
+
+/**
+ * Describes a set of insets for window content.
+ *
+ * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
+ * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
+ * with the adjusted properties.</p>
+ *
+ * @see View.OnApplyWindowInsetsListener
+ * @see View#onApplyWindowInsets(WindowInsets)
+ */
+public class WindowInsets {
+ private Rect mSystemWindowInsets;
+ private Rect mWindowDecorInsets;
+ private Rect mTempRect;
+
+ private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
+
+ /**
+ * Since new insets may be added in the future that existing apps couldn't
+ * know about, this fully empty constant shouldn't be made available to apps
+ * since it would allow them to inadvertently consume unknown insets by returning it.
+ * @hide
+ */
+ public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
+ mSystemWindowInsets = systemWindowInsets;
+ mWindowDecorInsets = windowDecorInsets;
+ }
+
+ /**
+ * Construct a new WindowInsets, copying all values from a source WindowInsets.
+ *
+ * @param src Source to copy insets from
+ */
+ public WindowInsets(WindowInsets src) {
+ mSystemWindowInsets = src.mSystemWindowInsets;
+ mWindowDecorInsets = src.mWindowDecorInsets;
+ }
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets) {
+ mSystemWindowInsets = systemWindowInsets;
+ mWindowDecorInsets = EMPTY_RECT;
+ }
+
+ /**
+ * Used to provide a safe copy of the system window insets to pass through
+ * to the existing fitSystemWindows method and other similar internals.
+ * @hide
+ */
+ public Rect getSystemWindowInsets() {
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+ mTempRect.set(mSystemWindowInsets);
+ return mTempRect;
+ }
+
+ /**
+ * Returns the left system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The left system window inset
+ */
+ public int getSystemWindowInsetLeft() {
+ return mSystemWindowInsets.left;
+ }
+
+ /**
+ * Returns the top system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The top system window inset
+ */
+ public int getSystemWindowInsetTop() {
+ return mSystemWindowInsets.top;
+ }
+
+ /**
+ * Returns the right system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The right system window inset
+ */
+ public int getSystemWindowInsetRight() {
+ return mSystemWindowInsets.right;
+ }
+
+ /**
+ * Returns the bottom system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The bottom system window inset
+ */
+ public int getSystemWindowInsetBottom() {
+ return mSystemWindowInsets.bottom;
+ }
+
+ /**
+ * Returns the left window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The left window decor inset
+ */
+ public int getWindowDecorInsetLeft() {
+ return mWindowDecorInsets.left;
+ }
+
+ /**
+ * Returns the top window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The top window decor inset
+ */
+ public int getWindowDecorInsetTop() {
+ return mWindowDecorInsets.top;
+ }
+
+ /**
+ * Returns the right window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The right window decor inset
+ */
+ public int getWindowDecorInsetRight() {
+ return mWindowDecorInsets.right;
+ }
+
+ /**
+ * Returns the bottom window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The bottom window decor inset
+ */
+ public int getWindowDecorInsetBottom() {
+ return mWindowDecorInsets.bottom;
+ }
+
+ /**
+ * Returns true if this WindowInsets has nonzero system window insets.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return true if any of the system window inset values are nonzero
+ */
+ public boolean hasSystemWindowInsets() {
+ return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 ||
+ mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0;
+ }
+
+ /**
+ * Returns true if this WindowInsets has nonzero window decor insets.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return true if any of the window decor inset values are nonzero
+ */
+ public boolean hasWindowDecorInsets() {
+ return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
+ mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0;
+ }
+
+ /**
+ * Returns true if this WindowInsets has any nonzero insets.
+ *
+ * @return true if any inset values are nonzero
+ */
+ public boolean hasInsets() {
+ return hasSystemWindowInsets() || hasWindowDecorInsets();
+ }
+
+ public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+ return result;
+ }
+
+ public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+ boolean right, boolean bottom) {
+ if (left || top || right || bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+ top ? 0 : mSystemWindowInsets.top,
+ right ? 0 : mSystemWindowInsets.right,
+ bottom ? 0 : mSystemWindowInsets.bottom);
+ return result;
+ }
+ return this;
+ }
+
+ public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+ return result;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets.set(0, 0, 0, 0);
+ return result;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+ boolean right, boolean bottom) {
+ if (left || top || right || bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
+ top ? 0 : mWindowDecorInsets.top,
+ right ? 0 : mWindowDecorInsets.right,
+ bottom ? 0 : mWindowDecorInsets.bottom);
+ return result;
+ }
+ return this;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets + " windowDecorInsets=" +
+ mWindowDecorInsets + "}";
+ }
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 53a4c0d0..d5a7d33 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -610,7 +610,10 @@
* screen is pressed, you will receive this first touch event. Usually
* the first touch event is consumed by the system since the user can
* not see what they are pressing on.
+ *
+ * @deprecated This flag has no effect.
*/
+ @Deprecated
public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
/** Window flag: as long as this window is visible to the user, keep
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 74dda77..893db89 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -86,8 +86,7 @@
public final static int FLAG_FILTERED = 0x04000000;
public final static int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
- public final static int FLAG_WOKE_HERE = 0x10000000;
- public final static int FLAG_BRIGHT_HERE = 0x20000000;
+ public final static int FLAG_INTERACTIVE = 0x20000000;
public final static int FLAG_PASS_TO_USER = 0x40000000;
// Flags used for indicating whether the internal and/or external input devices
@@ -735,11 +734,10 @@
* because it's the most fragile.
* @param event The key event.
* @param policyFlags The policy flags associated with the key.
- * @param isScreenOn True if the screen is already on
*
* @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
/**
* Called from the input reader thread before a motion is enqueued when the screen is off.
@@ -752,7 +750,7 @@
*
* @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 37121e2..9bfb00c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -710,19 +710,19 @@
break;
case com.android.internal.R.styleable.TextAppearance_shadowColor:
- shadowcolor = a.getInt(attr, 0);
+ shadowcolor = appearance.getInt(attr, 0);
break;
case com.android.internal.R.styleable.TextAppearance_shadowDx:
- dx = a.getFloat(attr, 0);
+ dx = appearance.getFloat(attr, 0);
break;
case com.android.internal.R.styleable.TextAppearance_shadowDy:
- dy = a.getFloat(attr, 0);
+ dy = appearance.getFloat(attr, 0);
break;
case com.android.internal.R.styleable.TextAppearance_shadowRadius:
- r = a.getFloat(attr, 0);
+ r = appearance.getFloat(attr, 0);
break;
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 02bd4ac..86c9fe3 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -57,10 +57,6 @@
}
@Override
- public void dispatchScreenState(boolean on) {
- }
-
- @Override
public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
}
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 5469b63..c957b67 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -20,6 +20,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import com.android.internal.app.ActionBarImpl;
import android.content.Context;
@@ -96,7 +97,7 @@
if (mLastSystemUiVisibility != 0) {
int newVis = mLastSystemUiVisibility;
onWindowSystemUiVisibilityChanged(newVis);
- requestFitSystemWindows();
+ requestApplyInsets();
}
}
}
@@ -152,7 +153,7 @@
}
if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
if (mActionBar != null) {
- requestFitSystemWindows();
+ requestApplyInsets();
}
}
}
@@ -190,19 +191,20 @@
}
@Override
- protected boolean fitSystemWindows(Rect insets) {
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
pullChildren();
final int vis = getWindowSystemUiVisibility();
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+ final Rect systemInsets = insets.getSystemWindowInsets();
// The top and bottom action bars are always within the content area.
- boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
+ boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
if (mActionBarBottom != null) {
- changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+ changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
}
- mBaseInnerInsets.set(insets);
+ mBaseInnerInsets.set(systemInsets);
computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
changed = true;
@@ -215,9 +217,9 @@
// We don't do any more at this point. To correctly compute the content/inner
// insets in all cases, we need to know the measured size of the various action
- // bar elements. fitSystemWindows() happens before the measure pass, so we can't
+ // bar elements. onApplyWindowInsets() happens before the measure pass, so we can't
// do that here. Instead we will take this up in onMeasure().
- return true;
+ return WindowInsets.EMPTY;
}
@Override
@@ -321,7 +323,7 @@
// the app's fitSystemWindows(). We do this before measuring the content
// view to keep the same semantics as the normal fitSystemWindows() call.
mLastInnerInsets.set(mInnerInsets);
- super.fitSystemWindows(mInnerInsets);
+ mContent.dispatchApplyWindowInsets(new WindowInsets(mInnerInsets));
}
measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 24e0b0a..7a4728d 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -49,6 +49,8 @@
jfieldID minDelay;
jfieldID fifoReservedEventCount;
jfieldID fifoMaxEventCount;
+ jfieldID stringType;
+ jfieldID requiredPermission;
} gSensorOffsets;
@@ -73,6 +75,9 @@
sensorOffsets.fifoReservedEventCount =
_env->GetFieldID(sensorClass, "mFifoReservedEventCount", "I");
sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount", "I");
+ sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
+ sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
+ "Ljava/lang/String;");
}
static jint
@@ -89,6 +94,8 @@
const SensorOffsets& sensorOffsets(gSensorOffsets);
jstring name = env->NewStringUTF(list->getName().string());
jstring vendor = env->NewStringUTF(list->getVendor().string());
+ jstring stringType = env->NewStringUTF(list->getStringType().string());
+ jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
env->SetObjectField(sensor, sensorOffsets.name, name);
env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
env->SetIntField(sensor, sensorOffsets.version, list->getVersion());
@@ -100,7 +107,11 @@
env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay());
env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
list->getFifoReservedEventCount());
- env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount());
+ env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
+ list->getFifoMaxEventCount());
+ env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+ env->SetObjectField(sensor, sensorOffsets.requiredPermission,
+ requiredPermission);
next++;
return size_t(next) < count ? next : 0;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b67a5a3..bd1f25f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -481,6 +481,13 @@
android:label="@string/permlab_writeProfile"
android:description="@string/permdesc_writeProfile" />
+ <!-- Allows an application to access data from sensors that the user uses to
+ measure what is happening inside his/her body, such as heart rate. -->
+ <permission android:name="android.permission.BODY_SENSORS"
+ android:permissionGroup="android.permission-group.PERSONAL_INFO"
+ android:label="@string/permlab_bodySensors"
+ android:description="@string/permdesc_bodySensors" />
+
<!-- =============================================================== -->
<!-- Permissions for accessing the device calendar -->
<!-- =============================================================== -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 02d4ad7..5c848f3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1333,6 +1333,14 @@
as your name and contact information. This means the app can identify you
and may send your profile information to others.</string>
+ <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=30] -->
+ <string name="permlab_bodySensors">body sensors (like heart rate monitors)
+ </string>
+ <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_bodySensors" product="default">Allows the app to
+ access data from sensors you use to measure what’s happening inside your
+ body, such as heart rate.</string>
+
<!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] -->
<string name="permlab_readSocialStream" product="default">read your social stream</string>
<string name="permdesc_readSocialStream" product="default">Allows the app
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index d2177ca..03addfd 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -8,7 +8,7 @@
<h2>In this document</h2>
<ol class="toc">
- <li><a href="#usage">How to Use CCS</a>
+ <li><a href="#connecting">Establishing a Connection</a>
<ol class="toc">
<li><a href="#auth">Authentication</a></li>
</ol>
@@ -46,19 +46,20 @@
<p class="note"><strong>Note:</strong> To try out this feature, sign up using
<a href="https://services.google.com/fb/forms/gcm/">this form</a>.</p>
-<p>The GCM Cloud Connection Server (CCS) is a connection server based on XMPP.
-CCS allows 3rd-party app servers (which you're
-responsible for implementing) to communicate
-with Android devices by establishing a persistent TCP connection with Google
-servers using the XMPP protocol. This communication is asynchronous and bidirectional.</p>
+<p>The GCM Cloud Connection Server (CCS) is an XMPP endpoint that provides a
+persistent, asynchronous, bidirectional connection to Google servers. The
+connection can be used to send and receive messages between your server and
+your users' GCM-connected devices.</p>
+
<p>You can continue to use the HTTP request mechanism to send messages to GCM
servers, side-by-side with CCS which uses XMPP. Some of the benefits of CCS include:</p>
+
<ul>
<li>The asynchronous nature of XMPP allows you to send more messages with fewer
resources.</li>
- <li>Communication is bidirectional—not only can the server send messages
-to the device, but the device can send messages back to the server.</li>
-<li>You can send messages back using the same connection used for receiving,
+ <li>Communication is bidirectional—not only can your server send messages
+to the device, but the device can send messages back to your server.</li>
+ <li>The device can send messages back using the same connection used for receiving,
thereby improving battery life.</li>
</ul>
@@ -73,22 +74,34 @@
<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
parameters and which connection server(s) supports them.</p>
+<h2 id="connecting">Establishing a Connection</h2>
-<h2 id="usage">How to Use CCS</h2>
+<p>CCS just uses XMPP as an authenticated transport layer, so you can use most
+XMPP libraries to manage the connection. For an example, see <a href="#smack">
+Java sample using the Smack library</a>.</p>
-<p>GCM Cloud Connection Server (CCS) is an XMPP endpoint, running on
-{@code http://gcm.googleapis.com} port 5235.</p>
+<p>The CCS XMPP endpoint runs at {@code gcm.googleapis.com:5235}. When testing
+functionality (with non-production users), you should instead connect to
+{@code gcm-staging.googleapis.com:5236} (note the different port). Testing on
+staging (a smaller environment where the latest CCS builds run) is beneficial
+both for isolating real users from test code, as well as for early detection of
+unexpected behavior changes.</p>
-<p>CCS requires a Transport Layer Security (TLS) connection. That means the XMPP
-client must initiate a TLS connection.
-For example in Java, you would call {@code setSocketFactory(SSLSocketFactory)}.</p>
+<p>The connection has two important requirements:</p>
-<p>CCS requires a SASL PLAIN authentication mechanism using
-{@code <your_GCM_Sender_Id>@gcm.googleapis.com} (GCM sender ID) and the
-API key as the password, where the sender ID and API key are the same as described
-in <a href="gs.html">Getting Started</a>.</p>
+<ul>
+ <li>You must initiate a Transport Layer Security (TLS) connection. Note that
+ CCS doesn't currently support the <a href="http://xmpp.org/rfcs/rfc3920.html"
+ class="external-link" target="_android">STARTTLS extension</a>.</li>
+ <li>CCS requires a SASL PLAIN authentication mechanism using
+ {@code <your_GCM_Sender_Id>@gcm.googleapis.com} (GCM sender ID)
+ and the API key as the password, where the sender ID and API key are the same
+ as described in <a href="gs.html">Getting Started</a>.</li>
+</ul>
-<p> You can use most XMPP libraries to interact with CCS.</p>
+<p>If at any point the connection fails, you should immediately reconnect.
+There is no need to back off after a disconnect that happens after
+authentication.</p>
<h3 id="auth">Authentication</h3>
@@ -100,11 +113,11 @@
</pre>
<h4>Server</h4>
<pre><str:features xmlns:str="http://etherx.jabber.org/streams">
- <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
- <mechanism>X-OAUTH2</mechanism>
- <mechanism>X-GOOGLE-TOKEN</mechanism>
- <mechanism>PLAIN</mechanism>
- </mechanisms>
+ <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
+ <mechanism>X-OAUTH2</mechanism>
+ <mechanism>X-GOOGLE-TOKEN</mechanism>
+ <mechanism>PLAIN</mechanism>
+ </mechanisms>
</str:features>
</pre>
@@ -118,16 +131,18 @@
<pre><success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/></pre>
<h2 id="format">Message Format</h2>
-<p>CCS uses normal XMPP <code><message></code> stanzas. The body of the message must be:
-</p>
+<p>Once the XMPP connection is established, CCS and your server use normal XMPP
+<code><message></code> stanzas to send JSON-encoded messages back and
+forth. The body of the <code><message></code> must be:</p>
<pre>
<gcm xmlns:google:mobile:data>
<em>JSON payload</em>
</gcm>
</pre>
-<p>The JSON payload for server-to-device is similar to what the GCM http endpoint
-uses, with these exceptions:</p>
+<p>The JSON payload for regular GCM messages is similar to
+<a href="http.html#request">what the GCM http endpoint uses</a>, with these
+exceptions:</p>
<ul>
<li>There is no support for multiple recipients.</li>
<li>{@code to} is used instead of {@code registration_ids}.</li>
@@ -136,14 +151,13 @@
{@code message_id} to identify a message sent from 3rd-party app servers to CCS.
Therefore, it's important that this {@code message_id} not only be unique, but
always present.</li>
-
-<li>For ACK/NACK messages that are special control messages, you also need to
-include a {@code message_type} field in the JSON message. The value can be either
-'ack' or 'nack'. For example:
-
-<pre>message_type = ('ack');</pre>
- </li>
</ul>
+
+<p>In addition to regular GCM messages, control messages are sent, indicated by
+the {@code message_type} field in the JSON object. The value can be either
+'ack' or 'nack', or 'control' (see formats below). Any GCM message with an
+unknown {@code message_type} can be ignored by your server.</p>
+
<p>For each device message your app server receives from CCS, it needs to send
an ACK message.
It never needs to send a NACK message. If you don't send an ACK for a message,
@@ -251,7 +265,9 @@
</message></pre>
-<p>The following table lists some of the more common NACK error codes.</p>
+<p>The following table lists NACK error codes. Unless otherwise
+indicated, a NACKed message should not be retried. Unexpected NACK error codes
+should be treated the same as {@code INTERNAL_SERVER_ERROR}.</p>
<p class="table-caption" id="table1">
<strong>Table 1.</strong> NACK error codes.</p>
@@ -262,8 +278,17 @@
<th>Description</th>
</tr>
<tr>
+<td>{@code BAD_ACK}</td>
+<td>The ACK message is improperly formed.</td>
+</tr>
+<tr>
<td>{@code BAD_REGISTRATION}</td>
-<td>The device has a registration ID, but it's invalid.</td>
+<td>The device has a registration ID, but it's invalid or expired.</td>
+</tr>
+<tr>
+<td>{@code CONNECTION_DRAINING}</td>
+<td>The message couldn't be processed because the connection is draining. The
+message should be immediately retried over another connection.</td>
</tr>
<tr>
<td>{@code DEVICE_UNREGISTERED}</td>
@@ -274,25 +299,20 @@
<td>The server encountered an error while trying to process the request.</td>
</tr>
<tr>
+<td>{@code INVALID_JSON}</td>
+<td>The JSON message payload was not valid.</td>
+</tr>
+<tr>
+<td>{@code QUOTA_EXCEEDED}</td>
+<td>The rate of messages to a particular registration ID (in other words, to a
+sender/device pair) is too high. If you want to retry the message, try using a slower
+rate.</td>
+</tr>
+<tr>
<td>{@code SERVICE_UNAVAILABLE}</td>
-<td>The CCS connection server is temporarily unavailable, try again later
-(using exponential backoff, etc.).</td>
-</tr>
-<tr>
-<td>{@code BAD_ACK}</td>
-<td>The ACK message is improperly formed.</td>
-</tr>
-<tr>
-<td>{@code AUTHENTICATION_FAILED}</td>
-<td>This is a 401 error indicating that there was an error authenticating the sender account.</td>
-</tr>
-<tr>
-<td>{@code INVALID_TTL}</td>
-<td>There was an error in the supplied "time to live" value.</td>
-</tr>
-<tr>
-<td>{@code JSON_TYPE_ERROR}</td>
-<td>There was an error in the supplied JSON data type.</td>
+<td>CCS is not currently able to process the message. The
+message should be retried over the same connection using exponential backoff
+with an initial delay of 1 second.</td>
</tr>
</table>
@@ -319,6 +339,28 @@
</message>
</pre>
+<h4 id="control">Control messages</h4>
+
+<p>Periodically, CCS needs to close down a connection to perform load balancing. Before it
+closes the connection, CCS sends a {@code CONNECTION_DRAINING} message to indicate that the connection is being drained
+and will be closed soon. "Draining" refers to shutting off the flow of messages coming into a
+connection, but allowing whatever is already in the pipeline to continue. When you receive
+a {@code CONNECTION_DRAINING} message, you should immediately begin sending messages to another CCS
+connection, opening a new connection if necessary. You should, however, keep the original
+connection open and continue receiving messages that may come over the connection (and
+ACKing them)—CCS will handle initiating a connection close when it is ready.</p>
+
+<p>The {@code CONNECTION_DRAINING} message looks like this:</p>
+<pre><message>
+ <data:gcm xmlns:data="google:mobile:data">
+ {
+ "message_type":"control"
+ "control_type":"CONNECTION_DRAINING"
+ }
+ </data:gcm>
+</message></pre>
+
+<p>{@code CONNECTION_DRAINING} is currently the only {@code control_type} supported.</p>
<h2 id="upstream">Upstream Messages</h2>
@@ -381,7 +423,7 @@
<p>Every message sent to CCS receives either an ACK or a NACK response. Messages
that haven't received one of these responses are considered pending. If the pending
-message count reaches 1000, the 3rd-party app server should stop sending new messages
+message count reaches 100, the 3rd-party app server should stop sending new messages
and wait for CCS to acknowledge some of the existing pending messages as illustrated in
figure 1:</p>
@@ -395,7 +437,7 @@
if there are too many unacknowledged messages. Therefore, the 3rd-party app server
should "ACK" upstream messages, received from the client application via CCS, as soon as possible
to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't
-apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party app server
+apply to these ACKs. Even if the pending message count reaches 100, the 3rd-party app server
should continue sending ACKs for messages received from CCS to avoid blocking delivery of new
upstream messages.</p>
@@ -795,7 +837,7 @@
PASSWORD = "API Key"
REGISTRATION_ID = "Registration Id of the target device"
-unacked_messages_quota = 1000
+unacked_messages_quota = 100
send_queue = []
# Return a random alphanumerical id
diff --git a/docs/html/google/play-services/maps.jd b/docs/html/google/play-services/maps.jd
index 68a84614..1fae770b 100644
--- a/docs/html/google/play-services/maps.jd
+++ b/docs/html/google/play-services/maps.jd
@@ -1,4 +1,4 @@
-page.title=Google Maps Android API
+page.title=Google Maps Android API v2
page.tags="mapview","location"
header.hide=1
@@ -12,14 +12,14 @@
</div>
<div class="col-6">
- <h1 itemprop="name" style="margin-bottom:0;">Google Maps Android API</h1>
+ <h1 itemprop="name" style="margin-bottom:0;">Google Maps Android API v2</h1>
<p itemprop="description">Allow your users explore the world with rich maps provided by
Google. Identify locations with <b>custom markers</b>, augment the map data
with <b>image overlays</b>, embed <b>one or more maps</b> as fragments,
and much more.</p>
<p>Explore the <a
href="{@docRoot}reference/com/google/android/gms/maps/package-summary.html"
->Google Maps Android API reference</a> or visit <a class="external-link"
+>Google Maps Android API v2 reference</a> or visit <a class="external-link"
href="https://developers.google.com/maps/documentation/android/">developers.google.com/maps</a>
for more information about adding maps to your app.</p>
</div>
@@ -31,7 +31,7 @@
<div class="col-6 normal-links">
<h3 style="clear:left">Key Developer Features</h3>
<h4>Add maps to your app</h4>
- <p>With version 2 of the Google Maps Android API, you can embed maps into an activity
+ <p>With Google Maps Android API v2, you can embed maps into an activity
as a fragment with a simple XML snippet. The new Maps offer exciting features such as 3D maps;
indoor, satellite, terrain, and hybrid maps;
vector-based tiles for efficient caching and drawing; animated transitions; and much more.
@@ -58,7 +58,7 @@
<div class="col-6 normal-links">
<h3 style="clear:left">Getting Started</h3>
<h4>1. Get the Google Play services SDK</h4>
- <p>The Google Maps Android APIs are part of the Google Play services platform.</p>
+ <p>Google Maps Android API v2 is part of the Google Play services platform.</p>
<p>To use Google Maps, <a href="{@docRoot}google/play-services/setup.html">set up
the Google Play services SDK</a>. Then see the <a class="external-link"
href="https://developers.google.com/maps/documentation/android/start#installing_the_google_maps_android_v2_api">
@@ -69,7 +69,7 @@
<p>Once you've installed the Google Play services package, the Google Maps sample is located in
<code><android-sdk>/extras/google-play-services/samples/maps</code> and shows you
- how to use the major components of the Google Maps Android APIs.
+ how to use the major components of Google Maps Android API v2.
</p>
<h4>3. Read the documentation</h4>
@@ -79,12 +79,12 @@
<p>For quick access while developing your Android apps, the
<a href="{@docRoot}reference/com/google/android/gms/maps/package-summary.html">Google Maps
- Android API reference</a> is available here on developer.android.com.</p>
+ Android API v2 reference</a> is available here on developer.android.com.</p>
- <p>Detailed documentation for the Google Maps Android APIs is available with the rest of the
+ <p>Detailed documentation for Google Maps Android API v2 is available with the rest of the
Google Maps developer documents at <a class="external-link"
href="https://developers.google.com/maps/documentation/android/">developers.google.com/maps</a>.
</p>
</div>
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 3137890..5df2629 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -104,7 +104,7 @@
dependencies {
compile 'com.android.support:appcompat-v7:+'
- <strong>compile 'com.google.android.gms:play-services:4.0.30'</strong>
+ <strong>compile 'com.google.android.gms:play-services:4.3.23'</strong>
}
</pre>
<p>Be sure you update this version number each time Google Play services is updated.</p>
@@ -235,4 +235,4 @@
<p>To then begin a connection to Google Play services, read <a
-href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services APIs</a>.</p>
\ No newline at end of file
+href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services APIs</a>.</p>
diff --git a/docs/html/images/gcm/CCS-ack.png b/docs/html/images/gcm/CCS-ack.png
index bce2ab2..4633157 100644
--- a/docs/html/images/gcm/CCS-ack.png
+++ b/docs/html/images/gcm/CCS-ack.png
Binary files differ
diff --git a/docs/html/images/tools/as-android.png b/docs/html/images/tools/as-android.png
new file mode 100644
index 0000000..7808ed1
--- /dev/null
+++ b/docs/html/images/tools/as-android.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointline.png b/docs/html/images/tools/as-breakpointline.png
new file mode 100644
index 0000000..9aea880
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointline.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointswindow.png b/docs/html/images/tools/as-breakpointswindow.png
new file mode 100644
index 0000000..a40b459
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointswindow.png
Binary files differ
diff --git a/docs/html/images/tools/as-capture.png b/docs/html/images/tools/as-capture.png
new file mode 100644
index 0000000..02f9f6f
--- /dev/null
+++ b/docs/html/images/tools/as-capture.png
Binary files differ
diff --git a/docs/html/images/tools/as-currentproc.png b/docs/html/images/tools/as-currentproc.png
new file mode 100644
index 0000000..4be8305
--- /dev/null
+++ b/docs/html/images/tools/as-currentproc.png
Binary files differ
diff --git a/docs/html/images/tools/as-ddmslog.png b/docs/html/images/tools/as-ddmslog.png
new file mode 100644
index 0000000..b53b8fe
--- /dev/null
+++ b/docs/html/images/tools/as-ddmslog.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugbutton.png b/docs/html/images/tools/as-debugbutton.png
new file mode 100644
index 0000000..55e95d1
--- /dev/null
+++ b/docs/html/images/tools/as-debugbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugdevices.png b/docs/html/images/tools/as-debugdevices.png
new file mode 100644
index 0000000..09a9d0e
--- /dev/null
+++ b/docs/html/images/tools/as-debugdevices.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugview.png b/docs/html/images/tools/as-debugview.png
new file mode 100644
index 0000000..0349147
--- /dev/null
+++ b/docs/html/images/tools/as-debugview.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugwindowbutton.png b/docs/html/images/tools/as-debugwindowbutton.png
new file mode 100644
index 0000000..9016778
--- /dev/null
+++ b/docs/html/images/tools/as-debugwindowbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-devicecapture.png b/docs/html/images/tools/as-devicecapture.png
new file mode 100644
index 0000000..3236a89
--- /dev/null
+++ b/docs/html/images/tools/as-devicecapture.png
Binary files differ
diff --git a/docs/html/images/tools/as-evalexpbutton.png b/docs/html/images/tools/as-evalexpbutton.png
new file mode 100644
index 0000000..85b3c74
--- /dev/null
+++ b/docs/html/images/tools/as-evalexpbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-launchavdm.png b/docs/html/images/tools/as-launchavdm.png
new file mode 100644
index 0000000..bf15981
--- /dev/null
+++ b/docs/html/images/tools/as-launchavdm.png
Binary files differ
diff --git a/docs/html/images/tools/as-monitorbutton.png b/docs/html/images/tools/as-monitorbutton.png
new file mode 100644
index 0000000..6bdc3a5
--- /dev/null
+++ b/docs/html/images/tools/as-monitorbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-record.png b/docs/html/images/tools/as-record.png
new file mode 100644
index 0000000..5f7fa99
--- /dev/null
+++ b/docs/html/images/tools/as-record.png
Binary files differ
diff --git a/docs/html/images/tools/as-restart.png b/docs/html/images/tools/as-restart.png
new file mode 100644
index 0000000..12d2923
--- /dev/null
+++ b/docs/html/images/tools/as-restart.png
Binary files differ
diff --git a/docs/html/images/tools/as-resumeprogrambutton.png b/docs/html/images/tools/as-resumeprogrambutton.png
new file mode 100644
index 0000000..8096937
--- /dev/null
+++ b/docs/html/images/tools/as-resumeprogrambutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-showdevview.png b/docs/html/images/tools/as-showdevview.png
new file mode 100644
index 0000000..602a6ad
--- /dev/null
+++ b/docs/html/images/tools/as-showdevview.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepintobutton.png b/docs/html/images/tools/as-stepintobutton.png
new file mode 100644
index 0000000..569d4ed
--- /dev/null
+++ b/docs/html/images/tools/as-stepintobutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoutbutton.png b/docs/html/images/tools/as-stepoutbutton.png
new file mode 100644
index 0000000..ef8871f
--- /dev/null
+++ b/docs/html/images/tools/as-stepoutbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoverbutton.png b/docs/html/images/tools/as-stepoverbutton.png
new file mode 100644
index 0000000..1c487df
--- /dev/null
+++ b/docs/html/images/tools/as-stepoverbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-variablesview.png b/docs/html/images/tools/as-variablesview.png
new file mode 100644
index 0000000..6a0b987
--- /dev/null
+++ b/docs/html/images/tools/as-variablesview.png
Binary files differ
diff --git a/docs/html/images/tools/as-varviewbutton.png b/docs/html/images/tools/as-varviewbutton.png
new file mode 100644
index 0000000..2ad4c58
--- /dev/null
+++ b/docs/html/images/tools/as-varviewbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-viewbreakbutton.png b/docs/html/images/tools/as-viewbreakbutton.png
new file mode 100644
index 0000000..22723d4
--- /dev/null
+++ b/docs/html/images/tools/as-viewbreakbutton.png
Binary files differ
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 9d5e8c1..6b63ba7 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -35,10 +35,10 @@
</div>
-
+
<div id="mac" class="docs" style="display:none">
-
+
<h3>Getting started on Mac</h3>
<ol>
@@ -62,7 +62,7 @@
<div id="linux" class="docs" style="display:none">
-
+
<h3>Getting started on Linux</h3>
<ol>
@@ -97,17 +97,23 @@
<li>Here are the steps to install Java and Eclipse, prior to installing
the Android SDK and ADT Plugin.
<ol>
- <li>If you are running a 64-bit distribution on your development
- machine, you need to install the <code>ia32-libs</code> package using
- <code>apt-get:</code>:
- <pre>apt-get install ia32-libs</pre>
+ <li><p>If you are running a 64-bit distribution on your development
+ machine, you need to install additional packages first. For Ubuntu 13.10 (Saucy Salamander)
+ and above, install the <code>libncurses5:i386</code>, <code>libstdc++6:i386</code>, and
+ <code>zlib1g:i386</code> packages using <code>apt-get</code>:</p>
+ <pre class="no-pretty-print">sudo dpkg --add-architecture i386
+sudo apt-get update
+sudo apt-get install libncurses5:i386 libstdc++6:i386 zlib1g:i386</pre>
+ <p>For earlier versions of Ubuntu, install the <code>ia32-libs</code> package using
+ <code>apt-get</code>:</p>
+ <pre class="no-pretty-print">apt-get install ia32-libs</pre>
</li>
- <li>Next, install Java: <pre>apt-get install sun-java6-jdk</pre></li>
- <li>The Ubuntu package manager does not currently offer an Eclipse 3.6
+ <li>Next, install Java: <pre class="no-pretty-print">apt-get install sun-java6-jdk</pre></li>
+ <li>The Ubuntu package manager does not currently offer an Eclipse 3.7
version for download, so we recommend that you download Eclipse from
eclipse.org (<a
- href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
- downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
+ href="http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>).
+ A Java or RCP version of Eclipse is recommended.</li>
<li>Follow the steps given in previous sections to install the SDK
and the ADT plugin. </li>
</ol>
@@ -137,7 +143,7 @@
// not running a compatible OS, so just show all the docs
$('.docs').show();
}
-
+
function showAll() {
$('.docs').each(function() {
if (!$(this).is(':visible')) {
diff --git a/docs/html/sdk/installing/studio-debug.jd b/docs/html/sdk/installing/studio-debug.jd
new file mode 100644
index 0000000..7e2efe3
--- /dev/null
+++ b/docs/html/sdk/installing/studio-debug.jd
@@ -0,0 +1,346 @@
+page.title=Debugging with Android Studio
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#runDebug">Run your App in Debug Mode</a></li>
+ <li><a href="#systemLog">Use the System Log</a>
+ <ol>
+ <li><a href="#systemLogWrite">Write log messages in your code</a></li>
+ <li><a href="#systemLogView">View the system log</a></li>
+ </ol>
+ </li>
+ <li><a href="#breakPoints">Work with Breakpoints</a>
+ <ol>
+ <li><a href="#breakPointsView">View and configure breakpoints</a></li>
+ <li><a href="#breakPointsDebug">Debug your app with breakpoints</a></li>
+ </ol>
+ </li>
+ <li><a href="#deviceMonitor">Analyze Runtime Metrics to Optimize your App</a></li>
+ <li><a href="#screenCap">Capture Screenshots and Videos</a></li>
+</ol>
+<h2>See also</h2>
+<ul>
+<li><a href="{@docRoot}sdk/installing/studio-tips.html">
+Android Studio Tips and Tricks</a></li>
+<li><a href="{@docRoot}tools/debugging/index.html">Debugging</a></li>
+<li><a href="{@docRoot}tools/help/monitor.html">Device Monitor</a></li>
+<li><a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a></li>
+</div>
+</div>
+
+<p>Android Studio enables you to debug apps running on the emulator or on an Android device.
+With Android Studio, you can:</p>
+
+<ul>
+ <li>Select a device to debug your app on.</li>
+ <li>View the system log.</li>
+ <li>Set breakpoints in your code.</li>
+ <li>Examine variables and evaluate expressions at run time.</li>
+ <li>Run the debugging tools from the Android SDK.</li>
+ <li>Capture screenshots and videos of your app.</li>
+</ul>
+
+<p>To debug your app, Android Studio builds a debuggable version of your app, connects
+to a device or to the emulator, installs the app and runs it. The IDE shows the system log
+while your app is running and provides debugging tools to filter log messages, work with
+breakpoints, and control the execution flow.</p>
+
+
+<h2 id="runDebug">Run your App in Debug Mode</h2>
+
+<div class="figure" style="width:419px">
+ <img src="{@docRoot}images/tools/as-debugdevices.png" alt=""/>
+ <p class="img-caption"><strong>Figure 1.</strong> The Choose Device window enables you to
+ select a physical Android device or a virtual device to debug your app.</p>
+</div>
+
+<p>To run your app in debug mode, you build an APK signed with a debug key and install it on a
+physical Android device or on the Android emulator.
+To set up an Android device for development, see <a href="{@docRoot}tools/device.html">Using
+Hardware Devices</a>. For more information about the emulator provided by the Android SDK, see
+<a href="{@docRoot}tools/devices/emulator.html">Using the Emulator.</a></p>
+
+<p>To debug your app in Android Studio:</p>
+
+<ol>
+ <li>Open your project in Android Studio.</li>
+ <li>Click <strong>Debug</strong> <img src="{@docRoot}images/tools/as-debugbutton.png"
+ style="vertical-align:bottom;margin:0;height:22px" alt=""/> in the toolbar.</li>
+ <li>On the <em>Choose Device</em> window, select a hardware device from the list or
+ choose a virtual device.</li>
+ <li>Click <strong>OK</strong>. Your app starts on the selected device.</li>
+</ol>
+
+<p>Figure 1 shows the <em>Choose Device</em> window. The list shows all the Android devices
+connected to your computer. Select <strong>Launch Emulator</strong> to use an Android virtual device
+instead. Click the ellipsis <img src="{@docRoot}images/tools/as-launchavdm.png"
+style="vertical-align:bottom;margin:0;height:19px" alt=""/> to open the
+<a href="{@docRoot}tools/devices/managing-avds.html">Android Virtual Device Manager</a>.</p>
+
+<p>Android Studio opens the <em>Debug</em> tool window when you debug your app. To open the
+<em>Debug</em> window manually, click <strong>Debug</strong>
+<img src="{@docRoot}images/tools/as-debugwindowbutton.png"
+alt="" style="vertical-align:bottom;margin:0;height:20px"/>.
+This window shows threads and variables in the <em>Debugger</em> tab, the device status in the
+<em>Console</em> tab, and the system log in the <em>Logcat</em> tab. The <em>Debug</em> tool
+window also provides other debugging tools covered in the following sections.</p>
+
+<img src="{@docRoot}images/tools/as-debugview.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> The Debug tool window in Android Studio showing
+the current thread and the object tree for a variable.</p>
+
+
+<h2 id="systemLog">Use the System Log</h2>
+
+<p>The system log shows system messages while you debug your app. These messages include
+information from apps running on the device. If you want to use the
+system log to debug your app, make sure your code writes log messages and prints the stack
+trace for exceptions while your app is in the development phase.</p>
+
+<h3 id="systemLogWrite">Write log messages in your code</h3>
+
+<p>To write log messages in your code, use the {@link android.util.Log} class. Log messages
+help you understand the execution flow by collecting the system debug output while you interact
+with your app. Log messages can tell you what part of your application failed. For more
+information about logging, see <a href="{@docRoot}tools/debugging/debugging-log.html">
+Reading and Writing Logs</a>.</p>
+
+<p>The following example shows how you might add log messages to determine if previous state
+information is available when your activity starts:</p>
+
+<pre>
+import android.util.Log;
+...
+public class MyActivity extends Activity {
+ private static final String TAG = MyActivity.class.getSimpleName();
+ ...
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ if (savedInstanceState != null) {
+ Log.d(TAG, "onCreate() Restoring previous state");
+ /* restore state */
+ } else {
+ Log.d(TAG, "onCreate() No saved state available");
+ /* initialize app */
+ }
+ }
+}
+</pre>
+
+<p>During development, your code can also catch exceptions and write the stack trace to the system
+log:</p>
+
+<pre>
+void someOtherMethod() {
+ try {
+ ...
+ } catch (SomeException e) {
+ Log.d(TAG, "someOtherMethod()", e);
+ }
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> Remove debug log messages and stack trace print calls from
+your code when you are ready to publish your app. You could do this by setting a <code>DEBUG</code>
+flag and placing debug log messages inside conditional statements.</p>
+
+
+<h3 id="systemLogView">View the system log</h3>
+
+<p>Both the <em>Android DDMS</em> (Dalvik Debug Monitor Server) and the <em>Debug</em> tool windows
+show the system log; however, the <em>Android DDMS</em> tool window lets you view only log messages
+for a particular process. To view the system log on the <em>Android DDMS</em> tool window:</p>
+
+<ol>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+ <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+ tool window.</li>
+ <li>If the system log is empty in the <em>Logcat view</em>, click <strong>Restart</strong>
+ <img src="{@docRoot}images/tools/as-restart.png" alt=""
+ style="vertical-align:bottom;margin:0;height:22px"/>.</li>
+</ol>
+
+<img src="{@docRoot}images/tools/as-ddmslog.png" alt="" />
+<p class="img-caption"><strong>Figure 4.</strong> The system log in the Android DDMS tool
+window.</p>
+
+<p>The <em>Android DDMS</em> tool window gives you access to some DDMS features from Android Studio.
+For more information about DDMS, see <a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.
+</p>
+
+<p>The system log shows messages from Android services and other Android apps. To filter the log
+messages to view only the ones you are interested in, use the tools in the <em>Android DDMS</em>
+window:</p>
+
+<ul>
+ <li>To show only log messages for a particular process, select the process in the
+ <em>Devices</em> view and then click <strong>Only Show Logcat from Selected
+ Process</strong> <img src="{@docRoot}images/tools/as-currentproc.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>. If the <em>Devices</em> view
+ is not available, click <strong>Restore Devices View</strong>
+ <img src="{@docRoot}images/tools/as-showdevview.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> on the right of the <em>Android
+ DDMS</em> tool window. This button is only visible when you hide the <em>Devices</em>
+ window.</li>
+ <li>To filter log messages by log level, select a level under <em>Log Level</em> on the top
+ of the <em>Android DDMS</em> window.</li>
+ <li>To show only log messages that contain a particular string, enter the string in the search
+ box and press <strong>Enter</strong>.</li>
+</ul>
+
+
+<h2 id="breakPoints">Work with Breakpoints</h2>
+
+<p>Breakpoints enable you to pause the execution of your app at a particular line of code, examine
+variables, evaluate expressions, and continue the execution line by line. Use breakpoints to
+determine the causes of run-time errors that you can't fix by looking at your code only. To debug
+your app using breakpoints:</p>
+
+<ol>
+ <li>Open the source file in which you want to set a breakpoint.</li>
+ <li>Locate the line where you want to set a breakpoint and click on it.</li>
+ <li>Click on the yellow portion of the side bar to the left of this line, as shown in figure 5.</li>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+</ol>
+
+<p>Android Studio pauses the execution of your app when it reaches the breakpoint. You can then
+use the tools in the <em>Debug</em> tool window to identify the cause of the error.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointline.png" alt="" />
+<p class="img-caption"><strong>Figure 5.</strong> A red dot appears next to the line when you set
+a breakpoint.</p>
+
+<h3 id="breakPointsView">View and configure breakpoints</h3>
+
+<p>To view all the breakpoints and configure breakpoint settings, click <strong>View
+Breakpoints</strong> <img src="{@docRoot}images/tools/as-viewbreakbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the left side of the <em>Debug</em> tool
+window. The <em>Breakpoints</em> window appears, as shown in figure 6.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointswindow.png" alt="" />
+<p class="img-caption"><strong>Figure 6.</strong> The Breakpoints window lists all the current
+breakpoints and includes behavior settings for each.</p>
+
+<p>The <em>Breakpoints</em> window lets you enable or disable each breakpoint from the
+list on the left. If a breakpoint is disabled, Android Studio does not pause your app when
+it hits that breakpoint. Select a breakpoint from the list to configure its settings.
+You can configure a breakpoint to be disabled at first and have the system enable it after a
+different breakpoint is hit. You can also configure whether a breakpoint should be disabled after
+it is hit. To set a breakpoint for any exception, select <strong>Exception Breakpoints</strong>
+in the list of breakpoints.</p>
+
+<h3 id="breakPointsDebug">Debug your app with breakpoints</h3>
+
+<p>After you set breakpoints in your code, click <strong>Rerun</strong>
+<img src="{@docRoot}images/tools/as-restart.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> to start the app again. When a breakpoint is
+hit, Android Studio pauses the app and highlights the breakpoint in the source code. The
+<em>Debug</em> tool window lets you examine variables and control the execution step by
+step:</p>
+
+<ul>
+ <li>
+ <p>To examine the object tree for a variable, expand it in the <em>Variables</em> view. If
+ the <em>Variables</em> view is not visible, click <strong>Restore Variables View</strong>
+ <img src="{@docRoot}images/tools/as-varviewbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To evaluate an expression at the current execution point, click <strong>Evaluate
+ Expression</strong> <img src="{@docRoot}images/tools/as-evalexpbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To advance to the next line in the code (without entering a method), click <strong>Step
+ Over</strong> <img src="{@docRoot}images/tools/as-stepoverbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To advance to the first line inside a method call, click <strong>Step
+ Into</strong> <img src="{@docRoot}images/tools/as-stepintobutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To advance to the next line outside the current method, click <strong>Step
+ Out</strong> <img src="{@docRoot}images/tools/as-stepoutbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To continue running the app normally, click <strong>Resume Program</strong>
+ <img src="{@docRoot}images/tools/as-resumeprogrambutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+</ul>
+
+<img src="{@docRoot}images/tools/as-variablesview.png" alt="" />
+<p class="img-caption"><strong>Figure 7.</strong> The Variables view in the Debug tool window.</p>
+
+
+<h2 id="deviceMonitor">Analyze Runtime Metrics to Optimize your App</h2>
+
+<p>Even if your application does not generate runtime errors, this does not mean it is free of
+problems. You should also consider the following issues:</p>
+
+<ul>
+ <li>Does your app use memory efficiently?</li>
+ <li>Does your app generate unnecessary network traffic?</li>
+ <li>What methods should you focus your attention on to improve the performance of your app?</li>
+ <li>Does your app behave properly when the user receives a phone call or a message?</li>
+</ul>
+
+<p>The Android Device Monitor is a stand-alone tool with a graphical user interface for serveral
+Android application debugging and analysis tools, including the Dalvik Debug Monitor Server (DDMS).
+You can use the Android Device Monitor to analyze memory usage, profile methods,
+monitor network traffic and simulate incoming calls and messages.</p>
+
+<p>To open the Android Device Monitor from Android Studio, click
+<strong>Monitor</strong> <img src="{@docRoot}images/tools/as-monitorbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the toolbar. The Android Device Monitor
+opens in a new window.</p>
+
+<p>For more information about the Android Device Monitor and DDMS, see
+<a href="{@docRoot}tools/help/monitor.html">Device Monitor</a> and
+<a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.</p>
+
+
+<h2 id="screenCap">Capture Screenshots and Videos</h2>
+
+<p>Android Studio enables you to capture a screenshot or a short video of the device screen
+while your app is running. Screenshots and videos are useful as promotional materials for your
+app, and you can also attach them to bug reports that you send to your development team.</p>
+
+<p>To take a screenshot of your app:</p>
+
+<ol>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+ <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+ tool window.</li>
+ <li>Click <strong>Screen Capture</strong> <img src="{@docRoot}images/tools/as-capture.png"
+ style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+ <em>Android DDMS</em> tool window.</li>
+ <li>Optional: To add a device frame around your screenshot, enable the <em>Frame screenshot</em>
+ option.</li>
+ <li>Click <strong>Save</strong>.</li>
+</ol>
+
+<p>To take a video recording of your app:</p>
+
+<ol>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+ <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+ tool window.</li>
+ <li>Click <strong>Screen Record</strong> <img src="{@docRoot}images/tools/as-record.png"
+ style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+ <em>Android DDMS</em> tool window.</li>
+ <li>Click <strong>Start Recording</strong>.</li>
+ <li>Interact with your app.</li>
+ <li>Click <strong>Stop Recording</strong>.</li>
+ <li>Enter a file name for the recording and click <strong>OK</strong>.</li>
+</ol>
\ No newline at end of file
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index c281644..b29b87c 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -38,6 +38,8 @@
Using the Layout Editor</a></li>
<li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
Building Your Project with Gradle</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
+ Debugging with Android Studio</a></li>
</ul>
</li>
<li><a href="<?cs var:toroot ?>sdk/exploring.html">
diff --git a/docs/image_sources/gcm/CCS-ack.graffle b/docs/image_sources/gcm/CCS-ack.graffle
new file mode 100644
index 0000000..addd456
--- /dev/null
+++ b/docs/image_sources/gcm/CCS-ack.graffle
@@ -0,0 +1,1580 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>ActiveLayerIndex</key>
+ <integer>0</integer>
+ <key>ApplicationVersion</key>
+ <array>
+ <string>com.omnigroup.OmniGrafflePro</string>
+ <string>139.18.0.187838</string>
+ </array>
+ <key>AutoAdjust</key>
+ <true/>
+ <key>BackgroundGraphic</key>
+ <dict>
+ <key>Bounds</key>
+ <string>{{0, 0}, {576.00002479553223, 733}}</string>
+ <key>Class</key>
+ <string>SolidGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>ID</key>
+ <integer>2</integer>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ </dict>
+ <key>BaseZoom</key>
+ <integer>0</integer>
+ <key>CanvasOrigin</key>
+ <string>{0, 0}</string>
+ <key>ColumnAlign</key>
+ <integer>1</integer>
+ <key>ColumnSpacing</key>
+ <real>36</real>
+ <key>CreationDate</key>
+ <string>2013-08-08 01:54:22 +0000</string>
+ <key>Creator</key>
+ <string>Katie McCormick</string>
+ <key>DisplayScale</key>
+ <string>1 0/72 in = 1.0000 in</string>
+ <key>GraphDocumentVersion</key>
+ <integer>8</integer>
+ <key>GraphicsList</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{89, 329}, {169, 44}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>250</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 Now app server can send\
+message no. 101}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{102, 266}, {114, 44}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>249</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 App server waits\
+for ack 1}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{153, 154}, {98, 44}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>244</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 Average\
+response time}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>226</integer>
+ <key>Position</key>
+ <real>0.375</real>
+ </dict>
+ <key>ID</key>
+ <integer>242</integer>
+ <key>Points</key>
+ <array>
+ <string>{263.00000095367432, 314.5}</string>
+ <string>{261, 99}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.112257</string>
+ <key>g</key>
+ <string>0.107007</string>
+ <key>r</key>
+ <string>0.934433</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>227</integer>
+ <key>Position</key>
+ <real>0.34722220897674561</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>227</integer>
+ <key>Position</key>
+ <real>0.3541666567325592</real>
+ </dict>
+ <key>ID</key>
+ <integer>241</integer>
+ <key>Points</key>
+ <array>
+ <string>{261, 99}</string>
+ <string>{262.50000071525574, 314.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.112257</string>
+ <key>g</key>
+ <string>0.107007</string>
+ <key>r</key>
+ <string>0.934433</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>226</integer>
+ <key>Position</key>
+ <real>0.375</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>227</integer>
+ </dict>
+ <key>ID</key>
+ <integer>240</integer>
+ <key>Points</key>
+ <array>
+ <string>{257.5, 336.5}</string>
+ <string>{288, 314.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.112257</string>
+ <key>g</key>
+ <string>0.107007</string>
+ <key>r</key>
+ <string>0.934433</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>239</integer>
+ <key>Points</key>
+ <array>
+ <string>{231, 288.50000116229057}</string>
+ <string>{231, 251.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.112257</string>
+ <key>g</key>
+ <string>0.107007</string>
+ <key>r</key>
+ <string>0.934433</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>238</integer>
+ <key>Position</key>
+ <real>0.56800001859664917</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>238</integer>
+ <key>Points</key>
+ <array>
+ <string>{231, 253}</string>
+ <string>{231, 315.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.112257</string>
+ <key>g</key>
+ <string>0.107007</string>
+ <key>r</key>
+ <string>0.934433</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{476, 33}, {49, 32}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>18</real>
+ </dict>
+ <key>ID</key>
+ <integer>230</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs36 \cf0 CCS}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{243, 35}, {101, 32}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>18</real>
+ </dict>
+ <key>ID</key>
+ <integer>229</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs36 \cf0 App Server}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>228</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 252}</string>
+ <string>{216, 252}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>227</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 314.5}</string>
+ <string>{216, 314.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>226</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 99}</string>
+ <string>{216, 99}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{393.69128000000001, 348.37441999999999}, {57, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>223</integer>
+ <key>Rotation</key>
+ <real>23</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 101}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{290.12054000000001, 420.17102}, {60, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>14</real>
+ </dict>
+ <key>ID</key>
+ <integer>222</integer>
+ <key>Rotation</key>
+ <real>341</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 100}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>220</integer>
+ <key>Points</key>
+ <array>
+ <string>{504, 351}</string>
+ <string>{288, 463}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{430.51697000000001, 279.19488999999999}, {44, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>14</real>
+ </dict>
+ <key>ID</key>
+ <integer>219</integer>
+ <key>Rotation</key>
+ <real>341</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack.. }</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{390.63733000000002, 258.42700000000002}, {44, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>14</real>
+ </dict>
+ <key>ID</key>
+ <integer>218</integer>
+ <key>Rotation</key>
+ <real>341</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 2}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{290.74178999999998, 239.21059}, {57, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>217</integer>
+ <key>Rotation</key>
+ <real>23</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 100}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{342.63623000000001, 185.82861}, {38, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>216</integer>
+ <key>Rotation</key>
+ <real>18</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no...}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{361.60431, 234}, {44, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>14</real>
+ </dict>
+ <key>ID</key>
+ <integer>209</integer>
+ <key>Rotation</key>
+ <real>341</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 1}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{351.16005999999999, 153.43960999999999}, {42, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>172</integer>
+ <key>Rotation</key>
+ <real>18</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 2}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{363, 117}, {42, 27}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>171</integer>
+ <key>Rotation</key>
+ <real>18</real>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 1}</string>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>169</integer>
+ <key>Points</key>
+ <array>
+ <string>{504, 200.62189000000001}</string>
+ <string>{288, 312.62189000000001}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>168</integer>
+ <key>Points</key>
+ <array>
+ <string>{504, 241.00763000000001}</string>
+ <string>{288, 353.00763000000001}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>167</integer>
+ <key>Points</key>
+ <array>
+ <string>{504, 279}</string>
+ <string>{288, 391}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>165</integer>
+ <key>Points</key>
+ <array>
+ <string>{289, 391}</string>
+ <string>{505, 492}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>164</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 353}</string>
+ <string>{504, 454}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>163</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 313}</string>
+ <string>{504, 414}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>162</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 180}</string>
+ <string>{504, 281}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>161</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 252}</string>
+ <string>{504, 353}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>160</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 139.5}</string>
+ <string>{504, 240.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>158</integer>
+ <key>Position</key>
+ <real>0.29398149251937866</real>
+ </dict>
+ <key>ID</key>
+ <integer>159</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 98.000000596046448}</string>
+ <string>{504, 199.00000476837158}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.934433</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0.122713</string>
+ </dict>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>157</integer>
+ <key>Position</key>
+ <real>0.060185186564922333</real>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>158</integer>
+ <key>Points</key>
+ <array>
+ <string>{504, 72}</string>
+ <string>{504, 504}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>ID</key>
+ <integer>157</integer>
+ <key>Points</key>
+ <array>
+ <string>{288, 72}</string>
+ <string>{288, 504}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Legacy</key>
+ <true/>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <dict>
+ <key>ShowsGrid</key>
+ <string>YES</string>
+ </dict>
+ <key>GuidesLocked</key>
+ <string>NO</string>
+ <key>GuidesVisible</key>
+ <string>YES</string>
+ <key>HPages</key>
+ <integer>1</integer>
+ <key>ImageCounter</key>
+ <integer>1</integer>
+ <key>KeepToScale</key>
+ <false/>
+ <key>Layers</key>
+ <array>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>Layer 1</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>YES</string>
+ </dict>
+ </array>
+ <key>LayoutInfo</key>
+ <dict>
+ <key>Animate</key>
+ <string>NO</string>
+ <key>circoMinDist</key>
+ <real>18</real>
+ <key>circoSeparation</key>
+ <real>0.0</real>
+ <key>layoutEngine</key>
+ <string>dot</string>
+ <key>neatoSeparation</key>
+ <real>0.0</real>
+ <key>twopiSeparation</key>
+ <real>0.0</real>
+ </dict>
+ <key>LinksVisible</key>
+ <string>NO</string>
+ <key>MagnetsVisible</key>
+ <string>NO</string>
+ <key>MasterSheets</key>
+ <array/>
+ <key>ModificationDate</key>
+ <string>2014-01-22 22:42:38 +0000</string>
+ <key>Modifier</key>
+ <string>Katie McCormick</string>
+ <key>NotesVisible</key>
+ <string>NO</string>
+ <key>Orientation</key>
+ <integer>2</integer>
+ <key>OriginVisible</key>
+ <string>NO</string>
+ <key>PageBreaks</key>
+ <string>YES</string>
+ <key>PrintInfo</key>
+ <dict>
+ <key>NSBottomMargin</key>
+ <array>
+ <string>float</string>
+ <string>41</string>
+ </array>
+ <key>NSHorizonalPagination</key>
+ <array>
+ <string>int</string>
+ <string>0</string>
+ </array>
+ <key>NSLeftMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSPaperSize</key>
+ <array>
+ <string>size</string>
+ <string>{612.00002479553223, 792}</string>
+ </array>
+ <key>NSPrintReverseOrientation</key>
+ <array>
+ <string>int</string>
+ <string>0</string>
+ </array>
+ <key>NSRightMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSTopMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ </dict>
+ <key>PrintOnePage</key>
+ <false/>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>RowAlign</key>
+ <integer>1</integer>
+ <key>RowSpacing</key>
+ <real>36</real>
+ <key>SheetTitle</key>
+ <string>Canvas 1</string>
+ <key>SmartAlignmentGuidesActive</key>
+ <string>YES</string>
+ <key>SmartDistanceGuidesActive</key>
+ <string>YES</string>
+ <key>UniqueID</key>
+ <integer>1</integer>
+ <key>UseEntirePage</key>
+ <false/>
+ <key>VPages</key>
+ <integer>1</integer>
+ <key>WindowInfo</key>
+ <dict>
+ <key>CurrentSheet</key>
+ <integer>0</integer>
+ <key>ExpandedCanvases</key>
+ <array>
+ <dict>
+ <key>name</key>
+ <string>Canvas 1</string>
+ </dict>
+ </array>
+ <key>Frame</key>
+ <string>{{170, 139}, {1218, 882}}</string>
+ <key>ListView</key>
+ <true/>
+ <key>OutlineWidth</key>
+ <integer>142</integer>
+ <key>RightSidebar</key>
+ <false/>
+ <key>ShowRuler</key>
+ <true/>
+ <key>Sidebar</key>
+ <true/>
+ <key>SidebarWidth</key>
+ <integer>120</integer>
+ <key>VisibleRegion</key>
+ <string>{{40.5, 0}, {534.5, 364}}</string>
+ <key>Zoom</key>
+ <real>2</real>
+ <key>ZoomValues</key>
+ <array>
+ <array>
+ <string>Canvas 1</string>
+ <real>2</real>
+ <real>1</real>
+ </array>
+ </array>
+ </dict>
+</dict>
+</plist>
diff --git a/libs/input/InputDispatcher.cpp b/libs/input/InputDispatcher.cpp
index 70ff085..7164a13 100644
--- a/libs/input/InputDispatcher.cpp
+++ b/libs/input/InputDispatcher.cpp
@@ -248,10 +248,10 @@
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
- // Reset the key repeat timer whenever we disallow key events, even if the next event
- // is not a key. This is to ensure that we abort a key repeat if the device is just coming
- // out of sleep.
- if (!mPolicy->isKeyRepeatEnabled()) {
+ // Reset the key repeat timer whenever normal dispatch is suspended while the
+ // device is in a non-interactive state. This is to ensure that we abort a key
+ // repeat if the device is just coming out of sleep.
+ if (!mDispatchEnabled) {
resetKeyRepeatLocked();
}
@@ -1135,30 +1135,6 @@
// For security reasons, we defer updating the touch state until we are sure that
// event injection will be allowed.
- //
- // FIXME In the original code, screenWasOff could never be set to true.
- // The reason is that the POLICY_FLAG_WOKE_HERE
- // and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw
- // EV_KEY, EV_REL and EV_ABS events. As it happens, the touch event was
- // actually enqueued using the policyFlags that appeared in the final EV_SYN
- // events upon which no preprocessing took place. So policyFlags was always 0.
- // In the new native input dispatcher we're a bit more careful about event
- // preprocessing so the touches we receive can actually have non-zero policyFlags.
- // Unfortunately we obtain undesirable behavior.
- //
- // Here's what happens:
- //
- // When the device dims in anticipation of going to sleep, touches
- // in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause
- // the device to brighten and reset the user activity timer.
- // Touches on other windows (such as the launcher window)
- // are dropped. Then after a moment, the device goes to sleep. Oops.
- //
- // Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE
- // instead of POLICY_FLAG_WOKE_HERE...
- //
- bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;
-
int32_t displayId = entry->displayId;
int32_t action = entry->action;
int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
@@ -1243,10 +1219,7 @@
isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
| InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
- if (! screenWasOff
- || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) {
- newTouchedWindowHandle = windowHandle;
- }
+ newTouchedWindowHandle = windowHandle;
break; // found touched window, exit window loop
}
}
@@ -2409,10 +2382,6 @@
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
- if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- flags |= AKEY_EVENT_FLAG_WOKE_HERE;
- }
-
bool needWake;
{ // acquire lock
mLock.lock();
@@ -2592,10 +2561,6 @@
mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
}
- if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- flags |= AKEY_EVENT_FLAG_WOKE_HERE;
- }
-
mLock.lock();
firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
keyEvent->getDeviceId(), keyEvent->getSource(),
diff --git a/libs/input/InputDispatcher.h b/libs/input/InputDispatcher.h
index 29854b2..9439124 100644
--- a/libs/input/InputDispatcher.h
+++ b/libs/input/InputDispatcher.h
@@ -211,9 +211,6 @@
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
- /* Returns true if automatic key repeating is enabled. */
- virtual bool isKeyRepeatEnabled() = 0;
-
/* Filters an input event.
* Return true to dispatch the event unmodified, false to consume the event.
* A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED
diff --git a/libs/input/tests/InputDispatcher_test.cpp b/libs/input/tests/InputDispatcher_test.cpp
index fc89a9b..7aac6ed 100644
--- a/libs/input/tests/InputDispatcher_test.cpp
+++ b/libs/input/tests/InputDispatcher_test.cpp
@@ -65,10 +65,6 @@
*outConfig = mConfig;
}
- virtual bool isKeyRepeatEnabled() {
- return true;
- }
-
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
return true;
}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 76c6eda..fb4de9e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -153,3 +153,23 @@
{
return static_cast<Sensor const*>(sensor)->getMinDelay();
}
+
+int ASensor_getFifoMaxEventCount(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getFifoMaxEventCount();
+}
+
+int ASensor_getFifoReservedEventCount(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getFifoReservedEventCount();
+}
+
+const char* ASensor_getStringType(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getStringType().string();
+}
+
+const char* ASensor_getRequiredPermission(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getRequiredPermission().string();
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 235fa0e..7128cfa 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2363,7 +2363,7 @@
}
private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
- int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
+ int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
win, fallbackEvent, policyFlags);
@@ -3802,12 +3802,13 @@
/** {@inheritDoc} */
@Override
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
+ final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
@@ -3819,7 +3820,7 @@
// This will prevent any keys other than the power button from waking the screen
// when the keyguard is hidden by another activity.
final boolean keyguardActive = (mKeyguardDelegate == null ? false :
- (isScreenOn ?
+ (interactive ?
mKeyguardDelegate.isShowingAndNotHidden() :
mKeyguardDelegate.isShowing()));
@@ -3831,7 +3832,7 @@
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
- + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
+ + " interactive=" + interactive + " keyguardActive=" + keyguardActive
+ " policyFlags=" + Integer.toHexString(policyFlags));
}
@@ -3840,18 +3841,11 @@
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
}
- // Basic policy based on screen state and keyguard.
- // FIXME: This policy isn't quite correct. We shouldn't care whether the screen
- // is on or off, really. We should care about whether the device is in an
- // interactive state or is in suspend pretending to be "off".
- // The primary screen might be turned off due to proximity sensor or
- // because we are presenting media on an auxiliary screen or remotely controlling
- // the device some other way (which is why we have an exemption here for injected
- // events).
+ // Basic policy based on interactive state.
int result;
boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
| WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
- if (isScreenOn || (isInjected && !isWakeKey)) {
+ if (interactive || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
} else {
@@ -3876,7 +3870,7 @@
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
- if (isScreenOn && !mVolumeDownKeyTriggered
+ if (interactive && !mVolumeDownKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeDownKeyTriggered = true;
mVolumeDownKeyTime = event.getDownTime();
@@ -3890,7 +3884,7 @@
}
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
if (down) {
- if (isScreenOn && !mVolumeUpKeyTriggered
+ if (interactive && !mVolumeUpKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeUpKeyTriggered = true;
cancelPendingPowerKeyAction();
@@ -3958,7 +3952,7 @@
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
- interceptPowerKeyDown(!isScreenOn || hungUp);
+ interceptPowerKeyDown(!interactive || hungUp);
} else {
if (interceptPowerKeyUp(canceled)) {
if ((mEndcallBehavior
@@ -3980,9 +3974,9 @@
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
+ mImmersiveModeConfirmation.onPowerKeyDown(interactive, event.getDownTime(),
isImmersiveMode(mLastSystemUiFlags));
- if (isScreenOn && !mPowerKeyTriggered
+ if (interactive && !mPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mPowerKeyTriggered = true;
mPowerKeyTime = event.getDownTime();
@@ -4008,7 +4002,7 @@
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
- interceptPowerKeyDown(!isScreenOn || hungUp
+ interceptPowerKeyDown(!interactive || hungUp
|| mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
} else {
mPowerKeyTriggered = false;
@@ -4141,15 +4135,12 @@
/** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
- int result = 0;
-
- final boolean isWakeMotion = (policyFlags
- & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
- if (isWakeMotion) {
- mPowerManager.wakeUp(whenNanos / 1000000);
- }
- return result;
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+ // We already know this is a wake motion so just wake up.
+ // Note that we would observe policyFlags containing
+ // FLAG_WAKE and FLAG_INTERACTIVE here.
+ mPowerManager.wakeUp(whenNanos / 1000000);
+ return 0;
}
void dispatchMediaKeyWithWakeLock(KeyEvent event) {
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 9379955..8df93f1 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -38,10 +38,13 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.concurrent.CountDownLatch;
import com.android.internal.app.IBatteryStats;
@@ -443,14 +446,14 @@
case NativeResponseCode.SERVICE_FOUND:
/* NNN uniqueId serviceName regType domain */
if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
- servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+ servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
clientId, servInfo);
break;
case NativeResponseCode.SERVICE_LOST:
/* NNN uniqueId serviceName regType domain */
if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
- servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+ servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
clientId, servInfo);
break;
@@ -463,7 +466,7 @@
case NativeResponseCode.SERVICE_REGISTERED:
/* NNN regId serviceName regType */
if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
- servInfo = new NsdServiceInfo(cooked[2], null, null);
+ servInfo = new NsdServiceInfo(cooked[2], null);
clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
id, clientId, servInfo);
break;
@@ -679,9 +682,22 @@
private boolean registerService(int regId, NsdServiceInfo service) {
if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
try {
- //Add txtlen and txtdata
- mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(),
+ Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
service.getServiceType(), service.getPort());
+
+ // Add TXT records as additional arguments.
+ Map<String, byte[]> txtRecords = service.getAttributes();
+ for (String key : txtRecords.keySet()) {
+ try {
+ // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
+ cmd.appendArg(String.format(Locale.US, "%s=%s", key,
+ new String(txtRecords.get(key), "UTF_8")));
+ } catch (UnsupportedEncodingException e) {
+ Slog.e(TAG, "Failed to encode txtRecord " + e);
+ }
+ }
+
+ mNativeConnector.execute(cmd);
} catch(NativeDaemonConnectorException e) {
Slog.e(TAG, "Failed to execute registerService " + e);
return false;
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
new file mode 100644
index 0000000..eb0ae6a
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+/**
+ * Interface used to update the actual display state.
+ */
+public interface DisplayBlanker {
+ void requestDisplayState(int state);
+}
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9ec1122..a5f9822 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -107,15 +107,9 @@
}
/**
- * Blanks the display, if supported.
+ * Sets the display state, if supported.
*/
- public void blankLocked() {
- }
-
- /**
- * Unblanks the display, if supported.
- */
- public void unblankLocked() {
+ public void requestDisplayStateLocked(int state) {
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 75f1f53..a77443d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -176,6 +176,11 @@
public String address;
/**
+ * Display state.
+ */
+ public int state = Display.STATE_ON;
+
+ /**
* The UID of the application that owns this display, or zero if it is owned by the system.
* <p>
* If the display is private, then only the owner can use it.
@@ -219,6 +224,7 @@
&& rotation == other.rotation
&& type == other.type
&& Objects.equal(address, other.address)
+ && state == other.state
&& ownerUid == other.ownerUid
&& Objects.equal(ownerPackageName, other.ownerPackageName);
}
@@ -241,6 +247,7 @@
rotation = other.rotation;
type = other.type;
address = other.address;
+ state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
}
@@ -260,6 +267,7 @@
if (address != null) {
sb.append(", address ").append(address);
}
+ sb.append(", state ").append(Display.stateToString(state));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 693f7d8..071417b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -121,10 +121,6 @@
private static final int MSG_REQUEST_TRAVERSAL = 4;
private static final int MSG_UPDATE_VIEWPORT = 5;
- private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
- private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
- private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
-
private final Context mContext;
private final DisplayManagerHandler mHandler;
private final Handler mUiHandler;
@@ -176,8 +172,9 @@
// Display power controller.
private DisplayPowerController mDisplayPowerController;
- // Set to true if all displays have been blanked by the power manager.
- private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN;
+ // The overall display state, independent of changes that might influence one
+ // display or another in particular.
+ private int mGlobalDisplayState = Display.STATE_UNKNOWN;
// Set to true when there are pending display changes that have yet to be applied
// to the surface flinger state.
@@ -315,21 +312,11 @@
}
}
- private void blankAllDisplaysFromPowerManagerInternal() {
+ private void requestGlobalDisplayStateInternal(int state) {
synchronized (mSyncRoot) {
- if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
- mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
- updateAllDisplayBlankingLocked();
- scheduleTraversalLocked(false);
- }
- }
- }
-
- private void unblankAllDisplaysFromPowerManagerInternal() {
- synchronized (mSyncRoot) {
- if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
- mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
- updateAllDisplayBlankingLocked();
+ if (mGlobalDisplayState != state) {
+ mGlobalDisplayState = state;
+ updateGlobalDisplayStateLocked();
scheduleTraversalLocked(false);
}
}
@@ -616,7 +603,7 @@
mDisplayDevices.add(device);
addLogicalDisplayLocked(device);
- updateDisplayBlankingLocked(device);
+ updateDisplayStateLocked(device);
scheduleTraversalLocked(false);
}
@@ -655,27 +642,20 @@
scheduleTraversalLocked(false);
}
- private void updateAllDisplayBlankingLocked() {
+ private void updateGlobalDisplayStateLocked() {
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
DisplayDevice device = mDisplayDevices.get(i);
- updateDisplayBlankingLocked(device);
+ updateDisplayStateLocked(device);
}
}
- private void updateDisplayBlankingLocked(DisplayDevice device) {
+ private void updateDisplayStateLocked(DisplayDevice device) {
// Blank or unblank the display immediately to match the state requested
- // by the power manager (if known).
+ // by the display power controller (if known).
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
- switch (mAllDisplayBlankStateFromPowerManager) {
- case DISPLAY_BLANK_STATE_BLANKED:
- device.blankLocked();
- break;
- case DISPLAY_BLANK_STATE_UNBLANKED:
- device.unblankLocked();
- break;
- }
+ device.requestDisplayStateLocked(mGlobalDisplayState);
}
}
@@ -816,9 +796,7 @@
+ device.getDisplayDeviceInfoLocked());
return;
}
- boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED)
- && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0;
- display.configureDisplayInTransactionLocked(device, isBlanked);
+ display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
// Update the viewports if needed.
if (!mDefaultViewport.valid
@@ -897,8 +875,7 @@
pw.println(" mOnlyCode=" + mOnlyCore);
pw.println(" mSafeMode=" + mSafeMode);
pw.println(" mPendingTraversal=" + mPendingTraversal);
- pw.println(" mAllDisplayBlankStateFromPowerManager="
- + mAllDisplayBlankStateFromPowerManager);
+ pw.println(" mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
pw.println(" mDefaultViewport=" + mDefaultViewport);
pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
@@ -1322,11 +1299,26 @@
private final class LocalService extends DisplayManagerInternal {
@Override
- public void initPowerManagement(DisplayPowerCallbacks callbacks, Handler handler,
+ public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
+ DisplayBlanker blanker = new DisplayBlanker() {
+ @Override
+ public void requestDisplayState(int state) {
+ // The order of operations is important for legacy reasons.
+ if (state == Display.STATE_OFF) {
+ requestGlobalDisplayStateInternal(state);
+ }
+
+ callbacks.onDisplayStateChange(state);
+
+ if (state != Display.STATE_OFF) {
+ requestGlobalDisplayStateInternal(state);
+ }
+ }
+ };
mDisplayPowerController = new DisplayPowerController(
- mContext, callbacks, handler, sensorManager);
+ mContext, callbacks, handler, sensorManager, blanker);
}
}
@@ -1343,16 +1335,6 @@
}
@Override
- public void blankAllDisplaysFromPowerManager() {
- blankAllDisplaysFromPowerManagerInternal();
- }
-
- @Override
- public void unblankAllDisplaysFromPowerManager() {
- unblankAllDisplaysFromPowerManagerInternal();
- }
-
- @Override
public DisplayInfo getDisplayInfo(int displayId) {
return getDisplayInfoInternal(displayId, Process.myUid());
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index dcf7da2..7abf88c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -45,6 +45,7 @@
import android.util.Slog;
import android.util.Spline;
import android.util.TimeUtils;
+import android.view.Display;
import java.io.PrintWriter;
@@ -185,6 +186,9 @@
// The sensor manager.
private final SensorManager mSensorManager;
+ // The display blanker.
+ private final DisplayBlanker mBlanker;
+
// The proximity sensor, or null if not available or needed.
private Sensor mProximitySensor;
@@ -349,7 +353,8 @@
* Creates the display power controller.
*/
public DisplayPowerController(Context context,
- DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager) {
+ DisplayPowerCallbacks callbacks, Handler handler,
+ SensorManager sensorManager, DisplayBlanker blanker) {
mHandler = new DisplayControllerHandler(handler.getLooper());
mCallbacks = callbacks;
@@ -357,6 +362,7 @@
mLights = LocalServices.getService(LightsManager.class);
mTwilight = LocalServices.getService(TwilightManager.class);
mSensorManager = sensorManager;
+ mBlanker = blanker;
final Resources resources = context.getResources();
@@ -520,8 +526,11 @@
}
private void initialize() {
- mPowerState = new DisplayPowerState(new ElectronBeam(), mCallbacks,
- mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
+ // Initialize the power state object for the default display.
+ // In the future, we might manage multiple displays independently.
+ mPowerState = new DisplayPowerState(mBlanker,
+ mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
+ new ElectronBeam(Display.DEFAULT_DISPLAY));
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -670,7 +679,7 @@
// Animate the screen on or off unless blocked.
if (mScreenOffBecauseOfProximity) {
// Screen off due to proximity.
- setScreenOn(false);
+ setScreenState(Display.STATE_OFF);
unblockScreenOn();
} else if (mPowerRequest.wantScreenOnAny()) {
// Want screen on.
@@ -681,7 +690,8 @@
// Turn the screen on. The contents of the screen may not yet
// be visible if the electron beam has not been dismissed because
// its last frame of animation is solid black.
- setScreenOn(true);
+ setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
+ ? Display.STATE_DOZING : Display.STATE_ON);
if (mPowerRequest.blockScreenOn
&& mPowerState.getElectronBeamLevel() == 0.0f) {
@@ -714,12 +724,12 @@
if (!mElectronBeamOnAnimator.isStarted()) {
if (!mElectronBeamOffAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 0.0f) {
- setScreenOn(false);
+ setScreenState(Display.STATE_OFF);
} else if (mPowerState.prepareElectronBeam(
mElectronBeamFadesConfig ?
ElectronBeam.MODE_FADE :
ElectronBeam.MODE_COOL_DOWN)
- && mPowerState.isScreenOn()) {
+ && mPowerState.getScreenState() != Display.STATE_OFF) {
mElectronBeamOffAnimator.start();
} else {
mElectronBeamOffAnimator.end();
@@ -752,9 +762,9 @@
private void blockScreenOn() {
if (!mScreenOnWasBlocked) {
mScreenOnWasBlocked = true;
+ mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
if (DEBUG) {
Slog.d(TAG, "Blocked screen on.");
- mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
}
}
}
@@ -769,11 +779,11 @@
}
}
- private void setScreenOn(boolean on) {
- if (mPowerState.isScreenOn() != on) {
- mPowerState.setScreenOn(on);
+ private void setScreenState(int state) {
+ if (mPowerState.getScreenState() != state) {
+ mPowerState.setScreenState(state);
try {
- if (on) {
+ if (state != Display.STATE_OFF) {
mBatteryStats.noteScreenOn();
} else {
mBatteryStats.noteScreenOff();
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index e1416d7..a5f8849 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -18,7 +18,6 @@
import com.android.server.lights.Light;
-import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
@@ -27,6 +26,7 @@
import android.util.IntProperty;
import android.util.Slog;
import android.view.Choreographer;
+import android.view.Display;
import java.io.PrintWriter;
@@ -54,12 +54,12 @@
private final Handler mHandler;
private final Choreographer mChoreographer;
- private final ElectronBeam mElectronBeam;
- private final DisplayPowerCallbacks mCallbacks;
+ private final DisplayBlanker mBlanker;
private final Light mBacklight;
+ private final ElectronBeam mElectronBeam;
private final PhotonicModulator mPhotonicModulator;
- private boolean mScreenOn;
+ private int mScreenState;
private int mScreenBrightness;
private boolean mScreenReady;
private boolean mScreenUpdatePending;
@@ -71,13 +71,12 @@
private Runnable mCleanListener;
- public DisplayPowerState(ElectronBeam electronBean,
- DisplayPowerCallbacks callbacks, Light backlight) {
+ public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
- mElectronBeam = electronBean;
- mCallbacks = callbacks;
+ mBlanker = blanker;
mBacklight = backlight;
+ mElectronBeam = electronBeam;
mPhotonicModulator = new PhotonicModulator();
// At boot time, we know that the screen is on and the electron beam
@@ -86,7 +85,7 @@
// Although we set the brightness to full on here, the display power controller
// will reset the brightness to a new level immediately before the changes
// actually have a chance to be applied.
- mScreenOn = true;
+ mScreenState = Display.STATE_ON;
mScreenBrightness = PowerManager.BRIGHTNESS_ON;
scheduleScreenUpdate();
@@ -122,25 +121,25 @@
};
/**
- * Sets whether the screen is on or off.
+ * Sets whether the screen is on, off, or dozing.
*/
- public void setScreenOn(boolean on) {
- if (mScreenOn != on) {
+ public void setScreenState(int state) {
+ if (mScreenState != state) {
if (DEBUG) {
- Slog.d(TAG, "setScreenOn: on=" + on);
+ Slog.d(TAG, "setScreenState: state=" + state);
}
- mScreenOn = on;
+ mScreenState = state;
mScreenReady = false;
scheduleScreenUpdate();
}
}
/**
- * Returns true if the screen is on.
+ * Gets the desired screen state.
*/
- public boolean isScreenOn() {
- return mScreenOn;
+ public int getScreenState() {
+ return mScreenState;
}
/**
@@ -155,7 +154,7 @@
}
mScreenBrightness = brightness;
- if (mScreenOn) {
+ if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate();
}
@@ -219,7 +218,7 @@
}
mElectronBeamLevel = level;
- if (mScreenOn) {
+ if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate(); // update backlight brightness
}
@@ -256,7 +255,7 @@
public void dump(PrintWriter pw) {
pw.println();
pw.println("Display Power State:");
- pw.println(" mScreenOn=" + mScreenOn);
+ pw.println(" mScreenState=" + Display.stateToString(mScreenState));
pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mScreenReady=" + mScreenReady);
pw.println(" mScreenUpdatePending=" + mScreenUpdatePending);
@@ -302,8 +301,9 @@
public void run() {
mScreenUpdatePending = false;
- int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
- if (mPhotonicModulator.setState(mScreenOn, brightness)) {
+ int brightness = mScreenState != Display.STATE_OFF
+ && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+ if (mPhotonicModulator.setState(mScreenState, brightness)) {
if (DEBUG) {
Slog.d(TAG, "Screen ready");
}
@@ -335,26 +335,26 @@
* Updates the state of the screen and backlight asynchronously on a separate thread.
*/
private final class PhotonicModulator {
- private static final boolean INITIAL_SCREEN_ON = false; // unknown, assume off
+ private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
private static final int INITIAL_BACKLIGHT = -1; // unknown
private final Object mLock = new Object();
- private boolean mPendingOn = INITIAL_SCREEN_ON;
+ private int mPendingState = INITIAL_SCREEN_STATE;
private int mPendingBacklight = INITIAL_BACKLIGHT;
- private boolean mActualOn = INITIAL_SCREEN_ON;
+ private int mActualState = INITIAL_SCREEN_STATE;
private int mActualBacklight = INITIAL_BACKLIGHT;
private boolean mChangeInProgress;
- public boolean setState(boolean on, int backlight) {
+ public boolean setState(int state, int backlight) {
synchronized (mLock) {
- if (on != mPendingOn || backlight != mPendingBacklight) {
+ if (state != mPendingState || backlight != mPendingBacklight) {
if (DEBUG) {
- Slog.d(TAG, "Requesting new screen state: on=" + on
- + ", backlight=" + backlight);
+ Slog.d(TAG, "Requesting new screen state: state="
+ + Display.stateToString(state) + ", backlight=" + backlight);
}
- mPendingOn = on;
+ mPendingState = state;
mPendingBacklight = backlight;
if (!mChangeInProgress) {
@@ -369,9 +369,9 @@
public void dump(PrintWriter pw) {
pw.println();
pw.println("Photonic Modulator State:");
- pw.println(" mPendingOn=" + mPendingOn);
+ pw.println(" mPendingState=" + Display.stateToString(mPendingState));
pw.println(" mPendingBacklight=" + mPendingBacklight);
- pw.println(" mActualOn=" + mActualOn);
+ pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mActualBacklight=" + mActualBacklight);
pw.println(" mChangeInProgress=" + mChangeInProgress);
}
@@ -381,35 +381,35 @@
public void run() {
// Apply pending changes until done.
for (;;) {
- final boolean on;
- final boolean onChanged;
+ final int state;
+ final boolean stateChanged;
final int backlight;
final boolean backlightChanged;
synchronized (mLock) {
- on = mPendingOn;
- onChanged = (on != mActualOn);
+ state = mPendingState;
+ stateChanged = (state != mActualState);
backlight = mPendingBacklight;
backlightChanged = (backlight != mActualBacklight);
- if (!onChanged && !backlightChanged) {
+ if (!stateChanged && !backlightChanged) {
mChangeInProgress = false;
break;
}
- mActualOn = on;
+ mActualState = state;
mActualBacklight = backlight;
}
if (DEBUG) {
- Slog.d(TAG, "Updating screen state: on=" + on
- + ", backlight=" + backlight);
+ Slog.d(TAG, "Updating screen state: state="
+ + Display.stateToString(state) + ", backlight=" + backlight);
}
- if (onChanged && on) {
- mCallbacks.unblankAllDisplays();
+ if (stateChanged && state != Display.STATE_OFF) {
+ mBlanker.requestDisplayState(state);
}
if (backlightChanged) {
mBacklight.setBrightness(backlight);
}
- if (onChanged && !on) {
- mCallbacks.blankAllDisplays();
+ if (stateChanged && state == Display.STATE_OFF) {
+ mBlanker.requestDisplayState(state);
}
}
diff --git a/services/core/java/com/android/server/display/ElectronBeam.java b/services/core/java/com/android/server/display/ElectronBeam.java
index 13816bb..18e4049 100644
--- a/services/core/java/com/android/server/display/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ElectronBeam.java
@@ -35,7 +35,6 @@
import android.os.Looper;
import android.util.FloatMath;
import android.util.Slog;
-import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
@@ -74,6 +73,8 @@
// See code for details.
private static final int DEJANK_FRAMES = 3;
+ private final int mDisplayId;
+
// Set to true when the animation context has been fully prepared.
private boolean mPrepared;
private int mMode;
@@ -118,8 +119,8 @@
*/
public static final int MODE_FADE = 2;
-
- public ElectronBeam() {
+ public ElectronBeam(int displayId) {
+ mDisplayId = displayId;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
}
@@ -139,7 +140,7 @@
// Get the display size and layer stack.
// This is not expected to change while the electron beam surface is showing.
- DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
mDisplayLayerStack = displayInfo.layerStack;
mDisplayWidth = displayInfo.getNaturalWidth();
mDisplayHeight = displayInfo.getNaturalHeight();
@@ -528,7 +529,8 @@
mSurface = new Surface();
mSurface.copyFrom(mSurfaceControl);
- mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, mSurfaceControl);
+ mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+ mDisplayId, mSurfaceControl);
mSurfaceLayout.onDisplayTransaction();
} finally {
SurfaceControl.closeTransaction();
@@ -687,11 +689,13 @@
*/
private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
private final DisplayManagerInternal mDisplayManagerInternal;
+ private final int mDisplayId;
private SurfaceControl mSurfaceControl;
public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
- SurfaceControl surfaceControl) {
+ int displayId, SurfaceControl surfaceControl) {
mDisplayManagerInternal = displayManagerInternal;
+ mDisplayId = displayId;
mSurfaceControl = surfaceControl;
mDisplayManagerInternal.registerDisplayTransactionListener(this);
}
@@ -710,8 +714,7 @@
return;
}
- DisplayInfo displayInfo =
- mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
switch (displayInfo.rotation) {
case Surface.ROTATION_0:
mSurfaceControl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index cb8f3e2..b8bf484 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -102,7 +102,7 @@
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
- private boolean mBlanked;
+ private int mState = Display.STATE_UNKNOWN;
public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
SurfaceControl.PhysicalDisplayInfo phys) {
@@ -135,6 +135,7 @@
mInfo.width = mPhys.width;
mInfo.height = mPhys.height;
mInfo.refreshRate = mPhys.refreshRate;
+ mInfo.state = mState;
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
@@ -172,15 +173,16 @@
}
@Override
- public void blankLocked() {
- mBlanked = true;
- SurfaceControl.blankDisplay(getDisplayTokenLocked());
- }
-
- @Override
- public void unblankLocked() {
- mBlanked = false;
- SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+ public void requestDisplayStateLocked(int state) {
+ if (mState != state) {
+ if (state == Display.STATE_OFF && mState != Display.STATE_OFF) {
+ SurfaceControl.blankDisplay(getDisplayTokenLocked());
+ } else if (state != Display.STATE_OFF && mState == Display.STATE_OFF) {
+ SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+ }
+ mState = state;
+ updateDeviceInfoLocked();
+ }
}
@Override
@@ -188,7 +190,12 @@
super.dumpLocked(pw);
pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
pw.println("mPhys=" + mPhys);
- pw.println("mBlanked=" + mBlanked);
+ pw.println("mState=" + Display.stateToString(mState));
+ }
+
+ private void updateDeviceInfoLocked() {
+ mInfo = null;
+ sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 7e357c0..5499af6 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -114,6 +114,7 @@
mInfo.copyFrom(mOverrideDisplayInfo);
mInfo.layerStack = mBaseDisplayInfo.layerStack;
mInfo.name = mBaseDisplayInfo.name;
+ mInfo.state = mBaseDisplayInfo.state;
} else {
mInfo.copyFrom(mBaseDisplayInfo);
}
@@ -212,6 +213,7 @@
mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
+ mBaseDisplayInfo.state = deviceInfo.state;
mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 007acf7..bfd8372c 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -194,12 +194,14 @@
private final int mDensityDpi;
private final boolean mSecure;
- private Surface mSurface;
+ private int mState;
private SurfaceTexture mSurfaceTexture;
+ private Surface mSurface;
private DisplayDeviceInfo mInfo;
public OverlayDisplayDevice(IBinder displayToken, String name,
- int width, int height, float refreshRate, int densityDpi, boolean secure,
+ int width, int height, float refreshRate,
+ int densityDpi, boolean secure, int state,
SurfaceTexture surfaceTexture) {
super(OverlayDisplayAdapter.this, displayToken);
mName = name;
@@ -208,6 +210,7 @@
mRefreshRate = refreshRate;
mDensityDpi = densityDpi;
mSecure = secure;
+ mState = state;
mSurfaceTexture = surfaceTexture;
}
@@ -230,6 +233,11 @@
}
}
+ public void setStateLocked(int state) {
+ mState = state;
+ mInfo = null;
+ }
+
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
@@ -247,6 +255,7 @@
}
mInfo.type = Display.TYPE_OVERLAY;
mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+ mInfo.state = mState;
}
return mInfo;
}
@@ -288,11 +297,12 @@
// Called on the UI thread.
@Override
- public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
+ public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, int state) {
synchronized (getSyncRoot()) {
IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
mDevice = new OverlayDisplayDevice(displayToken, mName,
- mWidth, mHeight, refreshRate, mDensityDpi, mSecure, surfaceTexture);
+ mWidth, mHeight, refreshRate, mDensityDpi, mSecure,
+ state, surfaceTexture);
sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
}
@@ -309,6 +319,17 @@
}
}
+ // Called on the UI thread.
+ @Override
+ public void onStateChanged(int state) {
+ synchronized (getSyncRoot()) {
+ if (mDevice != null) {
+ mDevice.setStateLocked(state);
+ sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ }
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println(" " + mName + ":");
pw.println(" mWidth=" + mWidth);
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index f1dd60a..06891f3 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -282,6 +282,7 @@
if (displayId == mDefaultDisplay.getDisplayId()) {
if (updateDefaultDisplayInfo()) {
relayout();
+ mListener.onStateChanged(mDefaultDisplayInfo.state);
} else {
dismiss();
}
@@ -301,7 +302,8 @@
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
int width, int height) {
- mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate);
+ mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate,
+ mDefaultDisplayInfo.state);
}
@Override
@@ -370,7 +372,9 @@
* Watches for significant changes in the overlay display window lifecycle.
*/
public interface Listener {
- public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate);
+ public void onWindowCreated(SurfaceTexture surfaceTexture,
+ float refreshRate, int state);
public void onWindowDestroyed();
+ public void onStateChanged(int state);
}
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
index 64b51c9..baae1d99 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
@@ -182,11 +182,49 @@
}
/**
+ * Send <Active Source> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendActiveSource(int physicalAddress) {
+ logWarning("<Active Source> not valid for the device type: " + mType
+ + " address:" + physicalAddress);
+ }
+
+ /**
+ * Send <Inactive Source> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendInactiveSource(int physicalAddress) {
+ logWarning("<Inactive Source> not valid for the device type: " + mType
+ + " address:" + physicalAddress);
+ }
+
+ /**
+ * Send <Image View On> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendImageViewOn() {
+ logWarning("<Image View On> not valid for the device type: " + mType);
+ }
+
+ /**
+ * Send <Text View On> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendTextViewOn() {
+ logWarning("<Text View On> not valid for the device type: " + mType);
+ }
+
+ /**
* Check if the connected sink device is in powered-on state. The default implementation
* simply returns false. Should be overriden by subclass to report the correct state.
*/
public boolean isSinkDeviceOn() {
- Log.w(TAG, "Not valid for the device type: " + mType);
+ logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
return false;
}
+
+ private void logWarning(String msg) {
+ Log.w(TAG, msg);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
index 0310264..f8cf11d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
@@ -66,14 +66,11 @@
// 1) Response for the queried power status request arrives. Update the status.
// 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
// into standby mode too.
- // 3) Broadcast <Report Physical Address> command from TV, which is sent while it boots up.
if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
mSinkDevicePowerStatus = params[0];
} else if (srcAddress == HdmiCec.ADDR_TV) {
if (opcode == HdmiCec.MESSAGE_STANDBY) {
mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
- } else if (opcode == HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS) {
- mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_ON;
}
}
super.handleMessage(srcAddress, dstAddress, opcode, params);
@@ -95,4 +92,38 @@
public boolean isSinkDeviceOn() {
return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
}
+
+ @Override
+ public void sendActiveSource(int physicalAddress) {
+ setIsActiveSource(true);
+ byte[] param = new byte[] {
+ (byte) ((physicalAddress >> 8) & 0xff),
+ (byte) (physicalAddress & 0xff)
+ };
+ getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
+ param);
+ }
+
+ @Override
+ public void sendInactiveSource(int physicalAddress) {
+ setIsActiveSource(false);
+ byte[] param = new byte[] {
+ (byte) ((physicalAddress >> 8) & 0xff),
+ (byte) (physicalAddress & 0xff)
+ };
+ getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE,
+ param);
+ }
+
+ @Override
+ public void sendImageViewOn() {
+ getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON,
+ HdmiCecService.EMPTY_PARAM);
+ }
+
+ @Override
+ public void sendTextViewOn() {
+ getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON,
+ HdmiCecService.EMPTY_PARAM);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
index aa496c5..0a4c719 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java
@@ -277,14 +277,7 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.setIsActiveSource(true);
- int physicalAddress = nativeGetPhysicalAddress(mNativePtr);
- byte[] param = new byte[] {
- (byte) ((physicalAddress >> 8) & 0xff),
- (byte) (physicalAddress & 0xff)
- };
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
- HdmiCec.MESSAGE_ACTIVE_SOURCE, param);
+ device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr));
}
}
@@ -293,9 +286,7 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.setIsActiveSource(false);
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
- HdmiCec.MESSAGE_INACTIVE_SOURCE, EMPTY_PARAM);
+ device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr));
}
}
@@ -304,8 +295,7 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
- HdmiCec.MESSAGE_IMAGE_VIEW_ON, EMPTY_PARAM);
+ device.sendImageViewOn();
}
}
@@ -314,8 +304,16 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
- HdmiCec.MESSAGE_TEXT_VIEW_ON, EMPTY_PARAM);
+ device.sendTextViewOn();
+ }
+ }
+
+ public void sendGiveDevicePowerStatus(IBinder b, int address) {
+ enforceAccessPermission();
+ synchronized (mLock) {
+ HdmiCecDevice device = getLogicalDeviceLocked(b);
+ nativeSendMessage(mNativePtr, device.getType(), address,
+ HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index e49382e..a32f7c1 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -183,6 +183,7 @@
InputChannel fromChannel, InputChannel toChannel);
private static native void nativeSetPointerSpeed(long ptr, int speed);
private static native void nativeSetShowTouches(long ptr, boolean enabled);
+ private static native void nativeSetInteractive(long ptr, boolean interactive);
private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
int repeat, int token);
private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
@@ -1360,14 +1361,13 @@
}
// Native callback.
- private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
- return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
- event, policyFlags, isScreenOn);
+ private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+ return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
// Native callback.
- private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
- return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+ private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+ return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing(
whenNanos, policyFlags);
}
@@ -1526,9 +1526,9 @@
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason);
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);
@@ -1696,5 +1696,10 @@
public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
return injectInputEventInternal(event, displayId, mode);
}
+
+ @Override
+ public void setInteractive(boolean interactive) {
+ nativeSetInteractive(mPtr, interactive);
+ }
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index eb7cc4c..855ae23 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1730,7 +1730,7 @@
private void updateScreenOn() {
synchronized (mRulesLock) {
try {
- mScreenOn = mPowerManager.isScreenOn();
+ mScreenOn = mPowerManager.isInteractive();
} catch (RemoteException e) {
// ignored; service lives in system_server
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 19d53cb..6224ed3 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -28,6 +28,7 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.hardware.input.InputManagerInternal;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
@@ -85,6 +86,7 @@
private final ScreenOnBlocker mScreenOnBlocker;
private final WindowManagerPolicy mPolicy;
private final ActivityManagerInternal mActivityManagerInternal;
+ private final InputManagerInternal mInputManagerInternal;
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
@@ -120,6 +122,7 @@
mScreenOnBlocker = screenOnBlocker;
mPolicy = policy;
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mHandler = new NotifierHandler(looper);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -194,73 +197,58 @@
}
/**
- * Called when the device is waking up from sleep and the
- * display is about to be turned on.
+ * Notifies that the device is changing interactive state.
*/
- public void onWakeUpStarted() {
+ public void onInteractiveStateChangeStarted(boolean interactive, int reason) {
if (DEBUG) {
- Slog.d(TAG, "onWakeUpStarted");
+ Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
+ + ", reason=" + reason);
}
synchronized (mLock) {
- if (mActualPowerState != POWER_STATE_AWAKE) {
- mActualPowerState = POWER_STATE_AWAKE;
- mPendingWakeUpBroadcast = true;
- if (!mScreenOnBlockerAcquired) {
- mScreenOnBlockerAcquired = true;
- mScreenOnBlocker.acquire();
+ if (interactive) {
+ // Waking up...
+ if (mActualPowerState != POWER_STATE_AWAKE) {
+ mActualPowerState = POWER_STATE_AWAKE;
+ mPendingWakeUpBroadcast = true;
+ if (!mScreenOnBlockerAcquired) {
+ mScreenOnBlockerAcquired = true;
+ mScreenOnBlocker.acquire();
+ }
+ updatePendingBroadcastLocked();
}
- updatePendingBroadcastLocked();
+ } else {
+ // Going to sleep...
+ mLastGoToSleepReason = reason;
}
+ mInputManagerInternal.setInteractive(interactive);
}
}
/**
- * Called when the device has finished waking up from sleep
- * and the display has been turned on.
+ * Notifies that the device has finished changing interactive state.
*/
- public void onWakeUpFinished() {
+ public void onInteractiveStateChangeFinished(boolean interactive) {
if (DEBUG) {
- Slog.d(TAG, "onWakeUpFinished");
- }
- }
-
- /**
- * Called when the device is going to sleep.
- */
- public void onGoToSleepStarted(int reason) {
- if (DEBUG) {
- Slog.d(TAG, "onGoToSleepStarted");
+ Slog.d(TAG, "onInteractiveChangeFinished");
}
synchronized (mLock) {
- mLastGoToSleepReason = reason;
- }
- }
-
- /**
- * Called when the device has finished going to sleep and the
- * display has been turned off.
- *
- * This is a good time to make transitions that we don't want the user to see,
- * such as bringing the key guard to focus. There's no guarantee for this,
- * however because the user could turn the device on again at any time.
- * Some things may need to be protected by other mechanisms that defer screen on.
- */
- public void onGoToSleepFinished() {
- if (DEBUG) {
- Slog.d(TAG, "onGoToSleepFinished");
- }
-
- synchronized (mLock) {
- if (mActualPowerState != POWER_STATE_ASLEEP) {
- mActualPowerState = POWER_STATE_ASLEEP;
- mPendingGoToSleepBroadcast = true;
- if (mUserActivityPending) {
- mUserActivityPending = false;
- mHandler.removeMessages(MSG_USER_ACTIVITY);
+ if (!interactive) {
+ // Finished going to sleep...
+ // This is a good time to make transitions that we don't want the user to see,
+ // such as bringing the key guard to focus. There's no guarantee for this,
+ // however because the user could turn the device on again at any time.
+ // Some things may need to be protected by other mechanisms that defer screen on.
+ if (mActualPowerState != POWER_STATE_ASLEEP) {
+ mActualPowerState = POWER_STATE_ASLEEP;
+ mPendingGoToSleepBroadcast = true;
+ if (mUserActivityPending) {
+ mUserActivityPending = false;
+ mHandler.removeMessages(MSG_USER_ACTIVITY);
+ }
+ updatePendingBroadcastLocked();
}
- updatePendingBroadcastLocked();
}
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6b2ca4c..7138c3e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -62,6 +62,7 @@
import android.util.Log;
import android.util.Slog;
import android.util.TimeUtils;
+import android.view.Display;
import android.view.WindowManagerPolicy;
import java.io.FileDescriptor;
@@ -209,6 +210,10 @@
// A bitfield that summarizes the state of all active wakelocks.
private int mWakeLockSummary;
+ // True if the device is in an interactive state.
+ private boolean mInteractive;
+ private boolean mInteractiveChanging;
+
// If true, instructs the display controller to wait for the proximity sensor to
// go negative before turning the screen on.
private boolean mRequestWaitForNegativeProximity;
@@ -217,11 +222,6 @@
private long mLastWakeTime;
private long mLastSleepTime;
- // True if we need to send a wake up or go to sleep finished notification
- // when the display is ready.
- private boolean mSendWakeUpFinishedNotificationWhenReady;
- private boolean mSendGoToSleepFinishedNotificationWhenReady;
-
// Timestamp of the last call to user activity.
private long mLastUserActivityTime;
private long mLastUserActivityTimeNoChangeLights;
@@ -265,11 +265,11 @@
// True if auto-suspend mode is enabled.
// Refer to autosuspend.h.
- private boolean mAutoSuspendModeEnabled;
+ private boolean mHalAutoSuspendModeEnabled;
// True if interactive mode is enabled.
// Refer to power.h.
- private boolean mInteractiveModeEnabled;
+ private boolean mHalInteractiveModeEnabled;
// True if the device is plugged into a power source.
private boolean mIsPowered;
@@ -289,10 +289,10 @@
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
// True to decouple auto-suspend mode from the display state.
- private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+ private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig;
// True to decouple interactive mode from the display state.
- private boolean mDecoupleInteractiveModeFromDisplayConfig;
+ private boolean mDecoupleHalInteractiveModeFromDisplayConfig;
// True if the device should wake up when plugged or unplugged.
private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
@@ -397,7 +397,6 @@
private native void nativeInit();
- private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
private static native void nativeAcquireSuspendBlocker(String name);
private static native void nativeReleaseSuspendBlocker(String name);
private static native void nativeSetInteractive(boolean enable);
@@ -411,13 +410,17 @@
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
+ mHalAutoSuspendModeEnabled = false;
+ mHalInteractiveModeEnabled = true;
mScreenOnBlocker = new ScreenOnBlockerImpl();
mWakefulness = WAKEFULNESS_AWAKE;
- }
+ mInteractive = true;
- nativeInit();
- nativeSetPowerState(true, true);
+ nativeInit();
+ nativeSetAutoSuspend(false);
+ nativeSetInteractive(true);
+ }
}
@Override
@@ -445,14 +448,6 @@
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
-
- // Forcibly turn the screen on at boot so that it is in a known power state.
- // We do this in init() rather than in the constructor because setting the
- // screen state requires a call into surface flinger which then needs to call back
- // into the activity manager to check permissions. Unfortunately the
- // activity manager is not running when the constructor is called, so we
- // have to defer setting the screen state until this point.
- mDisplayPowerCallbacks.unblankAllDisplays();
}
void setPolicy(WindowManagerPolicy policy) {
@@ -546,9 +541,9 @@
private void readConfigurationLocked() {
final Resources resources = mContext.getResources();
- mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+ mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
- mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+ mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
@@ -854,11 +849,6 @@
return false;
}
- // Called from native code.
- private void wakeUpFromNative(long eventTime) {
- wakeUpInternal(eventTime);
- }
-
private void wakeUpInternal(long eventTime) {
synchronized (mLock) {
if (wakeUpNoUpdateLocked(eventTime)) {
@@ -889,26 +879,16 @@
break;
}
- if (mWakefulness != WAKEFULNESS_DREAMING) {
- sendPendingNotificationsLocked();
- mNotifier.onWakeUpStarted();
- mSendWakeUpFinishedNotificationWhenReady = true;
- }
-
mLastWakeTime = eventTime;
- mWakefulness = WAKEFULNESS_AWAKE;
mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_AWAKE;
+ setInteractiveStateLocked(true, 0);
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
return true;
}
- // Called from native code.
- private void goToSleepFromNative(long eventTime, int reason) {
- goToSleepInternal(eventTime, reason);
- }
-
private void goToSleepInternal(long eventTime, int reason) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason)) {
@@ -945,14 +925,11 @@
break;
}
- sendPendingNotificationsLocked();
- mNotifier.onGoToSleepStarted(reason);
- mSendGoToSleepFinishedNotificationWhenReady = true;
-
mLastSleepTime = eventTime;
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_DOZING;
mSandmanSummoned = true;
+ setInteractiveStateLocked(false, reason);
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
@@ -994,6 +971,7 @@
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_DREAMING;
mSandmanSummoned = true;
+ setInteractiveStateLocked(true, 0);
return true;
}
@@ -1012,9 +990,27 @@
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_ASLEEP;
+ setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
return true;
}
+ private void setInteractiveStateLocked(boolean interactive, int reason) {
+ if (mInteractive != interactive) {
+ finishInteractiveStateChangeLocked();
+
+ mInteractive = interactive;
+ mInteractiveChanging = true;
+ mNotifier.onInteractiveStateChangeStarted(interactive, reason);
+ }
+ }
+
+ private void finishInteractiveStateChangeLocked() {
+ if (mInteractiveChanging) {
+ mNotifier.onInteractiveStateChangeFinished(mInteractive);
+ mInteractiveChanging = false;
+ }
+ }
+
/**
* Updates the global power state based on dirty bits recorded in mDirty.
*
@@ -1058,7 +1054,7 @@
// Phase 3: Send notifications, if needed.
if (mDisplayReady) {
- sendPendingNotificationsLocked();
+ finishInteractiveStateChangeLocked();
}
// Phase 4: Update suspend blocker.
@@ -1067,17 +1063,6 @@
updateSuspendBlockerLocked();
}
- private void sendPendingNotificationsLocked() {
- if (mSendWakeUpFinishedNotificationWhenReady) {
- mSendWakeUpFinishedNotificationWhenReady = false;
- mNotifier.onWakeUpFinished();
- }
- if (mSendGoToSleepFinishedNotificationWhenReady) {
- mSendGoToSleepFinishedNotificationWhenReady = false;
- mNotifier.onGoToSleepFinished();
- }
- }
-
/**
* Updates the value of mIsPowered.
* Sets DIRTY_IS_POWERED if a change occurred.
@@ -1197,48 +1182,45 @@
mWakeLockSummary |= WAKE_LOCK_CPU;
break;
case PowerManager.FULL_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
- mWakeLockSummary |= WAKE_LOCK_CPU
- | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
- }
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
- mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
- }
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
- mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
- }
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING
- || mWakefulness == WAKEFULNESS_DOZING) {
- mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
- }
+ mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
break;
case PowerManager.DOZE_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_DOZING) {
- mWakeLockSummary |= WAKE_LOCK_DOZE;
- }
+ mWakeLockSummary |= WAKE_LOCK_DOZE;
break;
}
}
+ // Cancel wake locks that make no sense based on the current state.
+ if (mWakefulness != WAKEFULNESS_DOZING) {
+ mWakeLockSummary &= ~WAKE_LOCK_DOZE;
+ }
+ if (mWakefulness == WAKEFULNESS_ASLEEP
+ || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+ mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
+ | WAKE_LOCK_BUTTON_BRIGHT);
+ if (mWakefulness == WAKEFULNESS_ASLEEP) {
+ mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+ }
+ }
+
+ // Infer implied wake locks where necessary based on the current state.
+ if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
+ } else if (mWakefulness == WAKEFULNESS_DREAMING) {
+ mWakeLockSummary |= WAKE_LOCK_CPU;
+ }
+ }
+
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
+ wakefulnessToString(mWakefulness)
@@ -1256,12 +1238,14 @@
*/
private void updateUserActivitySummaryLocked(long now, int dirty) {
// Update the status of the user activity timeout timer.
- if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
+ if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
+ | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
+ || mWakefulness == WAKEFULNESS_DREAMING
+ || mWakefulness == WAKEFULNESS_DOZING) {
final int screenOffTimeout = getScreenOffTimeoutLocked();
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
@@ -1585,8 +1569,6 @@
| DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
final int newScreenState = getDesiredScreenPowerStateLocked();
mDisplayPowerRequest.screenState = newScreenState;
- nativeSetPowerState(isScreenOnLocked(),
- newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
int screenBrightness = mScreenBrightnessSettingDefault;
float screenAutoBrightnessAdjustment = 0.0f;
@@ -1668,7 +1650,7 @@
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
new DisplayManagerInternal.DisplayPowerCallbacks() {
- private boolean mBlanked;
+ private int mDisplayState = Display.STATE_UNKNOWN;
@Override
public void onStateChanged() {
@@ -1699,6 +1681,33 @@
}
@Override
+ public void onDisplayStateChange(int state) {
+ // This method is only needed to support legacy display blanking behavior
+ // where the display's power state is coupled to suspend or to the power HAL.
+ // The order of operations matters here.
+ synchronized (mLock) {
+ if (mDisplayState != state) {
+ mDisplayState = state;
+ if (state == Display.STATE_OFF) {
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(false);
+ }
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(true);
+ }
+ } else {
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(true);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
public void acquireSuspendBlocker() {
mDisplaySuspendBlocker.acquire();
}
@@ -1709,37 +1718,9 @@
}
@Override
- public void blankAllDisplays() {
- synchronized (this) {
- mBlanked = true;
- mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
- if (!mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(false);
- }
- if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(true);
- }
- }
- }
-
- @Override
- public void unblankAllDisplays() {
- synchronized (this) {
- if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(false);
- }
- if (!mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(true);
- }
- mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
- mBlanked = false;
- }
- }
-
- @Override
public String toString() {
synchronized (this) {
- return "blanked=" + mBlanked;
+ return "state=" + Display.stateToString(mDisplayState);
}
}
};
@@ -1760,11 +1741,11 @@
// Disable auto-suspend if needed.
if (!autoSuspend) {
- if (mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(false);
+ if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(false);
}
- if (mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(true);
+ if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(true);
}
}
@@ -1790,11 +1771,11 @@
// Enable auto-suspend if needed.
if (autoSuspend) {
- if (mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(false);
+ if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(false);
}
- if (mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(true);
+ if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(true);
}
}
}
@@ -1821,42 +1802,32 @@
return false;
}
- private void setAutoSuspendModeLocked(boolean enable) {
- if (enable != mAutoSuspendModeEnabled) {
+ private void setHalAutoSuspendModeLocked(boolean enable) {
+ if (enable != mHalAutoSuspendModeEnabled) {
if (DEBUG) {
- Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+ Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
}
- mAutoSuspendModeEnabled = enable;
+ mHalAutoSuspendModeEnabled = enable;
nativeSetAutoSuspend(enable);
}
}
- private void setInteractiveModeLocked(boolean enable) {
- if (enable != mInteractiveModeEnabled) {
+ private void setHalInteractiveModeLocked(boolean enable) {
+ if (enable != mHalInteractiveModeEnabled) {
if (DEBUG) {
- Slog.d(TAG, "Setting interactive mode to " + enable);
+ Slog.d(TAG, "Setting HAL interactive mode to " + enable);
}
- mInteractiveModeEnabled = enable;
+ mHalInteractiveModeEnabled = enable;
nativeSetInteractive(enable);
}
}
- private boolean isScreenOnInternal() {
+ private boolean isInteractiveInternal() {
synchronized (mLock) {
- // XXX This is a temporary hack to let certain parts of the system pretend the
- // screen is still on even when dozing and we would normally want to report
- // screen off. Will be removed when the window manager is modified to use
- // the true blanking state of the display.
- return isScreenOnLocked()
- || mWakefulness == WAKEFULNESS_DOZING;
+ return mInteractive;
}
}
- private boolean isScreenOnLocked() {
- return mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING;
- }
-
private void handleBatteryStateChangedLocked() {
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();
@@ -2061,6 +2032,7 @@
pw.println("Power Manager State:");
pw.println(" mDirty=0x" + Integer.toHexString(mDirty));
pw.println(" mWakefulness=" + wakefulnessToString(mWakefulness));
+ pw.println(" mInteractive=" + mInteractive);
pw.println(" mIsPowered=" + mIsPowered);
pw.println(" mPlugType=" + mPlugType);
pw.println(" mBatteryLevel=" + mBatteryLevel);
@@ -2070,8 +2042,8 @@
pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
- pw.println(" mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
- pw.println(" mInteactiveModeEnabled=" + mInteractiveModeEnabled);
+ pw.println(" mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
+ pw.println(" mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
@@ -2079,10 +2051,6 @@
pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
- pw.println(" mSendWakeUpFinishedNotificationWhenReady="
- + mSendWakeUpFinishedNotificationWhenReady);
- pw.println(" mSendGoToSleepFinishedNotificationWhenReady="
- + mSendGoToSleepFinishedNotificationWhenReady);
pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
pw.println(" mLastUserActivityTimeNoChangeLights="
+ TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
@@ -2092,10 +2060,10 @@
pw.println();
pw.println("Settings and Configuration:");
- pw.println(" mDecoupleAutoSuspendModeFromDisplayConfig="
- + mDecoupleAutoSuspendModeFromDisplayConfig);
- pw.println(" mDecoupleInteractiveModeFromDisplayConfig="
- + mDecoupleInteractiveModeFromDisplayConfig);
+ pw.println(" mDecoupleHalAutoSuspendModeFromDisplayConfig="
+ + mDecoupleHalAutoSuspendModeFromDisplayConfig);
+ pw.println(" mDecoupleHalInteractiveModeFromDisplayConfig="
+ + mDecoupleHalInteractiveModeFromDisplayConfig);
pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig="
+ mWakeUpWhenPluggedOrUnpluggedConfig);
pw.println(" mSuspendWhenScreenOffDueToProximityConfig="
@@ -2684,10 +2652,10 @@
}
@Override // Binder call
- public boolean isScreenOn() {
+ public boolean isInteractive() {
final long ident = Binder.clearCallingIdentity();
try {
- return isScreenOnInternal();
+ return isInteractiveInternal();
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4aae5c1..b27c8d6 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -355,17 +355,16 @@
/* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */
@Override
- public int interceptKeyBeforeQueueing(
- KeyEvent event, int policyFlags, boolean isScreenOn) {
- return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+ return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}
/* Provides an opportunity for the window manager policy to intercept early
* motion event processing when the screen is off since these events are normally
* dropped. */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
- return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags);
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+ return mService.mPolicy.interceptWakeMotionBeforeQueueing(whenNanos, policyFlags);
}
/* Provides an opportunity for the window manager policy to process a key before
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 363e3d0..0a0ffd6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7038,7 +7038,6 @@
if (mDisplayEnabled) {
mInputMonitor.setEventDispatchingLw(enabled);
}
- sendScreenStatusToClientsLocked();
}
}
@@ -7158,23 +7157,6 @@
mPolicy.systemReady();
}
- // TODO(multidisplay): Call isScreenOn for each display.
- private void sendScreenStatusToClientsLocked() {
- final boolean on = mPowerManager.isScreenOn();
- final int numDisplays = mDisplayContents.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
- final int numWindows = windows.size();
- for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
- try {
- windows.get(winNdx).mClient.dispatchScreenState(on);
- } catch (RemoteException e) {
- // Ignored
- }
- }
- }
- }
-
// -------------------------------------------------------------
// Async Handler
// -------------------------------------------------------------
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index a00aaa8..54c9755 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -204,6 +204,11 @@
} else {
ALOGV("Logical Address Allocation success: %d", addr);
mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
+
+ // Broadcast <Report Physical Address> when a new logical address was allocated to let
+ // other devices discover the new logical device and its logical - physical address
+ // association.
+ sendReportPhysicalAddress();
}
return addr;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 3fccf53..a4f4a0b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -69,7 +69,7 @@
jmethodID notifyANR;
jmethodID filterInputEvent;
jmethodID interceptKeyBeforeQueueing;
- jmethodID interceptMotionBeforeQueueingWhenScreenOff;
+ jmethodID interceptWakeMotionBeforeQueueing;
jmethodID interceptKeyBeforeDispatching;
jmethodID dispatchUnhandledKey;
jmethodID checkInjectEventsPermission;
@@ -181,6 +181,7 @@
void setSystemUiVisibility(int32_t visibility);
void setPointerSpeed(int32_t speed);
void setShowTouches(bool enabled);
+ void setInteractive(bool interactive);
/* --- InputReaderPolicyInterface implementation --- */
@@ -201,7 +202,6 @@
virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
- virtual bool isKeyRepeatEnabled();
virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
virtual nsecs_t interceptKeyBeforeDispatching(
@@ -249,14 +249,12 @@
wp<PointerController> pointerController;
} mLocked;
+ volatile bool mInteractive;
+
void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
void ensureSpriteControllerLocked();
- // Power manager interactions.
- bool isScreenOn();
- bool isScreenBright();
-
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
static inline JNIEnv* jniEnv() {
@@ -268,7 +266,7 @@
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
- mLooper(looper) {
+ mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
@@ -624,11 +622,6 @@
}
}
-bool NativeInputManager::isKeyRepeatEnabled() {
- // Only enable automatic key repeating when the screen is on.
- return isScreenOn();
-}
-
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
Vector<sp<InputWindowHandle> > windowHandles;
@@ -740,12 +733,8 @@
InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
}
-bool NativeInputManager::isScreenOn() {
- return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
- return android_server_PowerManagerService_isScreenBright();
+void NativeInputManager::setInteractive(bool interactive) {
+ mInteractive = interactive;
}
bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
@@ -786,18 +775,18 @@
// - Ignore untrusted events and pass them along.
// - Ask the window manager what to do with normal events and trusted injected events.
// - For normal events wake and brighten the screen if currently off or dim.
+ if (mInteractive) {
+ policyFlags |= POLICY_FLAG_INTERACTIVE;
+ }
if ((policyFlags & POLICY_FLAG_TRUSTED)) {
nsecs_t when = keyEvent->getEventTime();
- bool isScreenOn = this->isScreenOn();
- bool isScreenBright = this->isScreenBright();
-
JNIEnv* env = jniEnv();
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
jint wmActions;
if (keyEventObj) {
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
- keyEventObj, policyFlags, isScreenOn);
+ keyEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
@@ -808,16 +797,6 @@
wmActions = 0;
}
- if (!(policyFlags & POLICY_FLAG_INJECTED)) {
- if (!isScreenOn) {
- policyFlags |= POLICY_FLAG_WOKE_HERE;
- }
-
- if (!isScreenBright) {
- policyFlags |= POLICY_FLAG_BRIGHT_HERE;
- }
- }
-
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
} else {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
@@ -830,24 +809,22 @@
// - No special filtering for injected events required at this time.
// - Filter normal events based on screen state.
// - For normal events brighten (but do not wake) the screen if currently dim.
+ if (mInteractive) {
+ policyFlags |= POLICY_FLAG_INTERACTIVE;
+ }
if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
- if (isScreenOn()) {
+ if (policyFlags & POLICY_FLAG_INTERACTIVE) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
-
- if (!isScreenBright()) {
- policyFlags |= POLICY_FLAG_BRIGHT_HERE;
- }
- } else {
+ } else if (policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED)) {
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
- gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
+ gServiceClassInfo.interceptWakeMotionBeforeQueueing,
when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
- "interceptMotionBeforeQueueingWhenScreenOff")) {
+ "interceptWakeMotionBeforeQueueing")) {
wmActions = 0;
}
- policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
} else {
@@ -1230,6 +1207,13 @@
im->setShowTouches(enabled);
}
+static void nativeSetInteractive(JNIEnv* env,
+ jclass clazz, jlong ptr, jboolean interactive) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setInteractive(interactive);
+}
+
static void nativeVibrate(JNIEnv* env,
jclass clazz, jlong ptr, jint deviceId, jlongArray patternObj,
jint repeat, jint token) {
@@ -1335,6 +1319,8 @@
(void*) nativeSetPointerSpeed },
{ "nativeSetShowTouches", "(JZ)V",
(void*) nativeSetShowTouches },
+ { "nativeSetInteractive", "(JZ)V",
+ (void*) nativeSetInteractive },
{ "nativeVibrate", "(JI[JII)V",
(void*) nativeVibrate },
{ "nativeCancelVibrate", "(JII)V",
@@ -1391,11 +1377,10 @@
"filterInputEvent", "(Landroid/view/InputEvent;I)Z");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
- "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
+ "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
- GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
- clazz,
- "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
+ GET_METHOD_ID(gServiceClassInfo.interceptWakeMotionBeforeQueueing, clazz,
+ "interceptWakeMotionBeforeQueueing", "(JI)I");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
"interceptKeyBeforeDispatching",
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 151e134..af09861 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -42,8 +42,6 @@
// ----------------------------------------------------------------------------
static struct {
- jmethodID wakeUpFromNative;
- jmethodID goToSleepFromNative;
jmethodID userActivityFromNative;
} gPowerManagerServiceClassInfo;
@@ -52,10 +50,6 @@
static jobject gPowerManagerServiceObj;
static struct power_module* gPowerModule;
-static Mutex gPowerManagerLock;
-static bool gScreenOn;
-static bool gScreenBright;
-
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
// Throttling interval for user activity calls.
@@ -73,16 +67,6 @@
return false;
}
-bool android_server_PowerManagerService_isScreenOn() {
- AutoMutex _l(gPowerManagerLock);
- return gScreenOn;
-}
-
-bool android_server_PowerManagerService_isScreenBright() {
- AutoMutex _l(gPowerManagerLock);
- return gScreenBright;
-}
-
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
// Tell the power HAL when user activity occurs.
if (gPowerModule && gPowerModule->powerHint) {
@@ -114,28 +98,6 @@
}
}
-void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
- if (gPowerManagerServiceObj) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
-
- env->CallVoidMethod(gPowerManagerServiceObj,
- gPowerManagerServiceClassInfo.wakeUpFromNative,
- nanoseconds_to_milliseconds(eventTime));
- checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
- }
-}
-
-void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
- if (gPowerManagerServiceObj) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
-
- env->CallVoidMethod(gPowerManagerServiceObj,
- gPowerManagerServiceClassInfo.goToSleepFromNative,
- nanoseconds_to_milliseconds(eventTime), 0);
- checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
- }
-}
-
// ----------------------------------------------------------------------------
static void nativeInit(JNIEnv* env, jobject obj) {
@@ -150,13 +112,6 @@
}
}
-static void nativeSetPowerState(JNIEnv* env,
- jclass clazz, jboolean screenOn, jboolean screenBright) {
- AutoMutex _l(gPowerManagerLock);
- gScreenOn = screenOn;
- gScreenBright = screenBright;
-}
-
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
@@ -195,8 +150,6 @@
/* name, signature, funcPtr */
{ "nativeInit", "()V",
(void*) nativeInit },
- { "nativeSetPowerState", "(ZZ)V",
- (void*) nativeSetPowerState },
{ "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeAcquireSuspendBlocker },
{ "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
@@ -229,12 +182,6 @@
jclass clazz;
FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
- GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
- "wakeUpFromNative", "(J)V");
-
- GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
- "goToSleepFromNative", "(JI)V");
-
GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
"userActivityFromNative", "(JII)V");
@@ -242,8 +189,6 @@
for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
gLastEventTime[i] = LLONG_MIN;
}
- gScreenOn = true;
- gScreenBright = true;
gPowerManagerServiceObj = NULL;
gPowerModule = NULL;
return 0;
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
index 0808b80..fb8153f 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -24,11 +24,7 @@
namespace android {
-extern bool android_server_PowerManagerService_isScreenOn();
-extern bool android_server_PowerManagerService_isScreenBright();
extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
-extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
-extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
} // namespace android
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 8b9f718..8392672 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -216,7 +216,7 @@
expectLastCall().atLeastOnce();
// expect to answer screen status during systemReady()
- expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+ expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
expectCurrentTime();
@@ -331,7 +331,7 @@
verifyAndReset();
// now turn screen off and verify REJECT rule
- expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
+ expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
expectSetUidNetworkRules(UID_A, true);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
@@ -341,7 +341,7 @@
verifyAndReset();
// and turn screen back on, verify ALLOW rule restored
- expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+ expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index c1305bc..89c951b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -80,6 +80,12 @@
}
@Override
+ public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+
public int[] getPackageGids(String packageName) throws NameNotFoundException {
throw new UnsupportedOperationException();
}
diff --git a/tests/CoreTests/android/core/NsdServiceInfoTest.java b/tests/CoreTests/android/core/NsdServiceInfoTest.java
new file mode 100644
index 0000000..5bf0167
--- /dev/null
+++ b/tests/CoreTests/android/core/NsdServiceInfoTest.java
@@ -0,0 +1,163 @@
+package android.core;
+
+import android.test.AndroidTestCase;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.StrictMode;
+import android.net.nsd.NsdServiceInfo;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+
+public class NsdServiceInfoTest extends AndroidTestCase {
+
+ public final static InetAddress LOCALHOST;
+ static {
+ // Because test.
+ StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
+ StrictMode.setThreadPolicy(policy);
+
+ InetAddress _host = null;
+ try {
+ _host = InetAddress.getLocalHost();
+ } catch (UnknownHostException e) { }
+ LOCALHOST = _host;
+ }
+
+ public void testLimits() throws Exception {
+ NsdServiceInfo info = new NsdServiceInfo();
+
+ // Non-ASCII keys.
+ boolean exceptionThrown = false;
+ try {
+ info.setAttribute("猫", "meow");
+ } catch (IllegalArgumentException e) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+ assertEmptyServiceInfo(info);
+
+ // ASCII keys with '=' character.
+ exceptionThrown = false;
+ try {
+ info.setAttribute("kitten=", "meow");
+ } catch (IllegalArgumentException e) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+ assertEmptyServiceInfo(info);
+
+ // Single key + value length too long.
+ exceptionThrown = false;
+ try {
+ String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+ "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+ "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+ "ooooooooooooooooooooooooooooong"; // 248 characters.
+ info.setAttribute("longcat", longValue); // Key + value == 255 characters.
+ } catch (IllegalArgumentException e) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+ assertEmptyServiceInfo(info);
+
+ // Total TXT record length too long.
+ exceptionThrown = false;
+ int recordsAdded = 0;
+ try {
+ for (int i = 100; i < 300; ++i) {
+ // 6 char key + 5 char value + 2 bytes overhead = 13 byte record length.
+ String key = String.format("key%d", i);
+ info.setAttribute(key, "12345");
+ recordsAdded++;
+ }
+ } catch (IllegalArgumentException e) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+ assertTrue(100 == recordsAdded);
+ assertTrue(info.getTxtRecord().length == 1300);
+ }
+
+ public void testParcel() throws Exception {
+ NsdServiceInfo emptyInfo = new NsdServiceInfo();
+ checkParcelable(emptyInfo);
+
+ NsdServiceInfo fullInfo = new NsdServiceInfo();
+ fullInfo.setServiceName("kitten");
+ fullInfo.setServiceType("_kitten._tcp");
+ fullInfo.setPort(4242);
+ fullInfo.setHost(LOCALHOST);
+ checkParcelable(fullInfo);
+
+ NsdServiceInfo noHostInfo = new NsdServiceInfo();
+ noHostInfo.setServiceName("kitten");
+ noHostInfo.setServiceType("_kitten._tcp");
+ noHostInfo.setPort(4242);
+ checkParcelable(noHostInfo);
+
+ NsdServiceInfo attributedInfo = new NsdServiceInfo();
+ attributedInfo.setServiceName("kitten");
+ attributedInfo.setServiceType("_kitten._tcp");
+ attributedInfo.setPort(4242);
+ attributedInfo.setHost(LOCALHOST);
+ attributedInfo.setAttribute("color", "pink");
+ attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8"));
+ attributedInfo.setAttribute("adorable", (String) null);
+ attributedInfo.setAttribute("sticky", "yes");
+ attributedInfo.setAttribute("siblings", new byte[] {});
+ attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128});
+ attributedInfo.removeAttribute("sticky");
+ checkParcelable(attributedInfo);
+
+ // Sanity check that we actually wrote attributes to attributedInfo.
+ assertTrue(attributedInfo.getAttributes().keySet().contains("adorable"));
+ String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8");
+ assertTrue(sound.equals("にゃあ"));
+ byte[] edgeCases = attributedInfo.getAttributes().get("edge cases");
+ assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128}));
+ assertFalse(attributedInfo.getAttributes().keySet().contains("sticky"));
+ }
+
+ public void checkParcelable(NsdServiceInfo original) {
+ // Write to parcel.
+ Parcel p = Parcel.obtain();
+ Bundle writer = new Bundle();
+ writer.putParcelable("test_info", original);
+ writer.writeToParcel(p, 0);
+
+ // Extract from parcel.
+ p.setDataPosition(0);
+ Bundle reader = p.readBundle();
+ reader.setClassLoader(NsdServiceInfo.class.getClassLoader());
+ NsdServiceInfo result = reader.getParcelable("test_info");
+
+ // Assert equality of base fields.
+ assertEquality(original.getServiceName(), result.getServiceName());
+ assertEquality(original.getServiceType(), result.getServiceType());
+ assertEquality(original.getHost(), result.getHost());
+ assertTrue(original.getPort() == result.getPort());
+
+ // Assert equality of attribute map.
+ Map<String, byte[]> originalMap = original.getAttributes();
+ Map<String, byte[]> resultMap = result.getAttributes();
+ assertEquality(originalMap.keySet(), resultMap.keySet());
+ for (String key : originalMap.keySet()) {
+ assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
+ }
+ }
+
+ public void assertEquality(Object expected, Object result) {
+ assertTrue(expected == result || expected.equals(result));
+ }
+
+ public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
+ assertTrue(null == shouldBeEmpty.getTxtRecord());
+ }
+}
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index bf35db4..a0b2d1a 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -97,6 +97,7 @@
setLowProfile(true);
setFullscreen(true);
setContentView(R.layout.dream);
+ setScreenBright(false);
mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 281337c..908fc47 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -28,7 +28,7 @@
public class BridgePowerManager implements IPowerManager {
@Override
- public boolean isScreenOn() throws RemoteException {
+ public boolean isInteractive() throws RemoteException {
return true;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index df576d2..d32f6ee 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -58,11 +58,6 @@
}
@Override
- public void dispatchScreenState(boolean on) throws RemoteException {
- // pass for now.
- }
-
- @Override
public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index a79fba1..2ef3d5f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -114,6 +114,7 @@
"android.os.*", // for android.os.Handler
"android.database.ContentObserver", // for Digital clock
"com.android.i18n.phonenumbers.*", // for TextView with autolink attribute
+ "android.app.DatePickerDialog", // b.android.com/28318
},
excludeClasses,
new String[] {