Merge "Fix scrolling when the bound target offset is too high"
diff --git a/Android.mk b/Android.mk
index 9b3436e..57091cc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -183,6 +183,7 @@
core/java/android/print/IWriteResultCallback.aidl \
core/java/android/printservice/IPrintService.aidl \
core/java/android/printservice/IPrintServiceClient.aidl \
+ core/java/android/service/dreams/IDozeHardware.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
core/java/android/service/dreams/IDreamService.aidl \
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
diff --git a/api/current.txt b/api/current.txt
index 46ff80c..c20fc19 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6119,6 +6119,7 @@
method public final void unregisterContentObserver(android.database.ContentObserver);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
method public static void validateSyncExtrasBundle(android.os.Bundle);
+ field public static final java.lang.String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
field public static final java.lang.String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
field public static final java.lang.String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
@@ -7661,6 +7662,7 @@
field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
+ field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
@@ -11495,6 +11497,25 @@
field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4
field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; // 0x1
field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0; // 0x0
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_CLOUDY_WEATHER = 10; // 0xa
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_COOL_WHITE_FLUORESCENT = 14; // 0xe
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D50 = 23; // 0x17
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D55 = 20; // 0x14
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D65 = 21; // 0x15
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D75 = 22; // 0x16
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT = 1; // 0x1
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT_FLUORESCENT = 12; // 0xc
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_DAY_WHITE_FLUORESCENT = 13; // 0xd
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_FINE_WEATHER = 9; // 0x9
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_FLASH = 4; // 0x4
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_FLUORESCENT = 2; // 0x2
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_ISO_STUDIO_TUNGSTEN = 24; // 0x18
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_SHADE = 11; // 0xb
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_A = 17; // 0x11
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_B = 18; // 0x12
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_C = 19; // 0x13
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_TUNGSTEN = 3; // 0x3
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_WHITE_FLUORESCENT = 15; // 0xf
field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS = 2; // 0x2
field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY = 3; // 0x3
field public static final int SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256; // 0x100
@@ -11645,9 +11666,11 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
@@ -21642,6 +21665,8 @@
field public static final java.lang.String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
field public static final java.lang.String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
field public static final java.lang.String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
+ field public static final java.lang.String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
+ field public static final java.lang.String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
field public static final java.lang.String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
field public static final java.lang.String EXTRA_OUTPUT = "output";
field public static final java.lang.String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
@@ -21760,6 +21785,7 @@
method public static android.net.Uri getContentUriForPath(java.lang.String);
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
field public static final java.lang.String DEFAULT_SORT_ORDER = "title_key";
+ field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
field public static final android.net.Uri EXTERNAL_CONTENT_URI;
field public static final java.lang.String EXTRA_MAX_BYTES = "android.provider.MediaStore.extra.MAX_BYTES";
field public static final android.net.Uri INTERNAL_CONTENT_URI;
@@ -21795,6 +21821,11 @@
field public static final java.lang.String NAME = "name";
}
+ public static final class MediaStore.Audio.Radio {
+ ctor public MediaStore.Audio.Radio();
+ field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
+ }
+
public static final class MediaStore.Files {
ctor public MediaStore.Files();
method public static android.net.Uri getContentUri(java.lang.String);
@@ -27145,6 +27176,7 @@
method public final V put(K, V);
method public final synchronized int putCount();
method public final V remove(K);
+ method public void resize(int);
method public final synchronized int size();
method protected int sizeOf(K, V);
method public final synchronized java.util.Map<K, V> snapshot();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a8716bf..4f0683c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -824,7 +824,7 @@
}
/**
- * Return the LoaderManager for this fragment, creating it if needed.
+ * Return the LoaderManager for this activity, creating it if needed.
*/
public LoaderManager getLoaderManager() {
if (mLoaderManager != null) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 3fc933d..8694416 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -192,6 +192,14 @@
*/
public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
+ /**
+ * This is the Android platform's generic MIME type to match any MIME
+ * type of the form "{@link #CURSOR_ITEM_BASE_TYPE}/{@code SUB_TYPE}".
+ * {@code SUB_TYPE} is the sub-type of the application-dependent
+ * content, e.g., "audio", "video", "playlist".
+ */
+ public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
+
/** @hide */
public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
/** @hide */
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index f3828b0..e9d82af 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -24,7 +24,7 @@
import java.io.PrintWriter;
/**
- * An abstract class that performs asynchronous loading of data. While Loaders are active
+ * A class that performs asynchronous loading of data. While Loaders are active
* they should monitor the source of their data and deliver new results when the contents
* change. See {@link android.app.LoaderManager} for more detail.
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 40d9606..b648930 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1257,6 +1257,15 @@
public static final String FEATURE_TELEVISION = "android.hardware.type.television";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: This is a device dedicated to showing UI
+ * on a watch. A watch here is defined to be a device worn on the body, perhaps on
+ * the wrist. The user is very close when interacting with the device.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_WATCH = "android.hardware.type.watch";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports printing.
*/
diff --git a/core/java/android/debug/JNITest.java b/core/java/android/debug/JNITest.java
deleted file mode 100644
index 2ce374a..0000000
--- a/core/java/android/debug/JNITest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2006 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.debug;
-
-/**
- * Simple JNI verification test.
- */
-public class JNITest {
-
- public JNITest() {
- }
-
- public int test(int intArg, double doubleArg, String stringArg) {
- int[] intArray = { 42, 53, 65, 127 };
-
- return part1(intArg, doubleArg, stringArg, intArray);
- }
-
- private native int part1(int intArg, double doubleArg, String stringArg,
- int[] arrayArg);
-
- private int part2(double doubleArg, int fromArray, String stringArg) {
- int result;
-
- System.out.println(stringArg + " : " + (float) doubleArg + " : " +
- fromArray);
- result = part3(stringArg);
-
- return result + 6;
- }
-
- private static native int part3(String stringArg);
-}
-
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index a581982..cbd6ec3 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1670,6 +1670,110 @@
public static final int LENS_STATE_MOVING = 1;
//
+ // Enumeration values for CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ //
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT = 1;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_FLUORESCENT = 2;
+
+ /**
+ * <p>Incandescent light</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_TUNGSTEN = 3;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_FLASH = 4;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_FINE_WEATHER = 9;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_CLOUDY_WEATHER = 10;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_SHADE = 11;
+
+ /**
+ * <p>D 5700 - 7100K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT_FLUORESCENT = 12;
+
+ /**
+ * <p>N 4600 - 5400K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_DAY_WHITE_FLUORESCENT = 13;
+
+ /**
+ * <p>W 3900 - 4500K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_COOL_WHITE_FLUORESCENT = 14;
+
+ /**
+ * <p>WW 3200 - 3700K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_WHITE_FLUORESCENT = 15;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_A = 17;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_B = 18;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_C = 19;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D55 = 20;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D65 = 21;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D75 = 22;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D50 = 23;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_ISO_STUDIO_TUNGSTEN = 24;
+
+ //
// Enumeration values for CaptureResult#STATISTICS_SCENE_FLICKER
//
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 32526bd..bd9ba2f 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1459,6 +1459,36 @@
new Key<Float>("android.sensor.temperature", float.class);
/**
+ * <p>A reference illumination source roughly matching the current scene
+ * illumination, which is used to describe the sensor color space
+ * transformations.</p>
+ * <p>The values in this tag correspond to the values defined for the
+ * EXIF LightSource tag. These illuminants are standard light sources
+ * that are often used for calibrating camera devices.</p>
+ * @see #SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_TUNGSTEN
+ * @see #SENSOR_REFERENCE_ILLUMINANT_FLASH
+ * @see #SENSOR_REFERENCE_ILLUMINANT_FINE_WEATHER
+ * @see #SENSOR_REFERENCE_ILLUMINANT_CLOUDY_WEATHER
+ * @see #SENSOR_REFERENCE_ILLUMINANT_SHADE
+ * @see #SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_DAY_WHITE_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_COOL_WHITE_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_WHITE_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_STANDARD_A
+ * @see #SENSOR_REFERENCE_ILLUMINANT_STANDARD_B
+ * @see #SENSOR_REFERENCE_ILLUMINANT_STANDARD_C
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D55
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D65
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D75
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D50
+ * @see #SENSOR_REFERENCE_ILLUMINANT_ISO_STUDIO_TUNGSTEN
+ */
+ public static final Key<Integer> SENSOR_REFERENCE_ILLUMINANT =
+ new Key<Integer>("android.sensor.referenceIlluminant", int.class);
+
+ /**
* <p>A per-device calibration transform matrix to be applied after the
* color space transform when rendering the raw image buffer.</p>
* <p>This matrix is expressed as a 3x3 matrix in row-major-order, and
@@ -1536,6 +1566,39 @@
new Key<float[]>("android.sensor.profileToneCurve", float[].class);
/**
+ * <p>The worst-case divergence between Bayer green channels.</p>
+ * <p>This value is an estimate of the worst case split between the
+ * Bayer green channels in the red and blue rows in the sensor color
+ * filter array.</p>
+ * <p>The green split is calculated as follows:</p>
+ * <ol>
+ * <li>A representative 5x5 pixel window W within the active
+ * sensor array is chosen.</li>
+ * <li>The arithmetic mean of the green channels from the red
+ * rows (mean_Gr) within W is computed.</li>
+ * <li>The arithmetic mean of the green channels from the blue
+ * rows (mean_Gb) within W is computed.</li>
+ * <li>The maximum ratio R of the two means is computed as follows:
+ * <code>R = max((mean_Gr + 1)/(mean_Gb + 1), (mean_Gb + 1)/(mean_Gr + 1))</code></li>
+ * </ol>
+ * <p>The ratio R is the green split divergence reported for this property,
+ * which represents how much the green channels differ in the mosaic
+ * pattern. This value is typically used to determine the treatment of
+ * the green mosaic channels when demosaicing.</p>
+ * <p>The green split value can be roughly interpreted as follows:</p>
+ * <ul>
+ * <li>R < 1.03 is a negligible split (<3% divergence).</li>
+ * <li>1.20 <= R >= 1.03 will require some software
+ * correction to avoid demosaic errors (3-20% divergence).</li>
+ * <li>R > 1.20 will require strong software correction to produce
+ * a usuable image (>20% divergence).</li>
+ * </ul>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<Float> SENSOR_GREEN_SPLIT =
+ new Key<Float>("android.sensor.greenSplit", float.class);
+
+ /**
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index c3f4807..8e0ff08 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1460,10 +1460,11 @@
}
/**
- * Use this function for customized exception handling.
- * customized method call this method for all unknown case
- * @param code exception code
- * @param msg exception message
+ * Throw an exception with the given message. Not intended for use
+ * outside the Parcel class.
+ *
+ * @param code Used to determine which exception class to throw.
+ * @param msg The exception message.
*/
public final void readException(int code, String msg) {
switch (code) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 0439eeb..4d4c337 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -191,6 +191,18 @@
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
/**
+ * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
+ * if no other wake locks are held.
+ * <p>
+ * This is used by the dream manager to implement doze mode. It currently
+ * has no effect unless the power manager is in the dozing state.
+ * </p>
+ *
+ * {@hide}
+ */
+ public static final int DOZE_WAKE_LOCK = 0x00000040;
+
+ /**
* Mask for the wake lock level component of a combined wake lock level and flags integer.
*
* @hide
@@ -437,6 +449,7 @@
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+ case DOZE_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f69cad0..bd576afb 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -169,6 +169,14 @@
*/
public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
/**
+ * The name of the Intent-extra used to define the genre.
+ */
+ public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
+ /**
+ * The name of the Intent-extra used to define the radio channel.
+ */
+ public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
+ /**
* The name of the Intent-extra used to define the search focus. The search focus
* indicates whether the search should be for things related to the artist, album
* or song that is identified by the other extras.
@@ -1389,6 +1397,11 @@
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
/**
+ * The MIME type for an audio track.
+ */
+ public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
+
+ /**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
@@ -1859,6 +1872,13 @@
*/
public static final String DEFAULT_SORT_ORDER = ALBUM_KEY;
}
+
+ public static final class Radio {
+ /**
+ * The MIME type for entries in this table.
+ */
+ public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
+ }
}
public static final class Video {
diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java
new file mode 100644
index 0000000..b5e7f43
--- /dev/null
+++ b/core/java/android/service/dreams/DozeHardware.java
@@ -0,0 +1,77 @@
+/**
+ * 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.service.dreams;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides access to low-level hardware features that a dream may use to provide
+ * a richer user experience while dozing.
+ * <p>
+ * This class contains functions that should be called by the dream to configure
+ * hardware before starting to doze and allowing the application processor to suspend.
+ * For example, the dream may provide the hardware with enough information to render
+ * some content on its own without any further assistance from the application processor.
+ * </p><p>
+ * This object is obtained by calling {@link DreamService#getDozeHardware()}.
+ * </p>
+ *
+ * @hide experimental
+ */
+public final class DozeHardware {
+ private static final String TAG = "DozeHardware";
+
+ public static final String MSG_ENABLE_MCU = "enable_mcu";
+
+ public static final byte[] VALUE_ON = "on".getBytes();
+ public static final byte[] VALUE_OFF = "off".getBytes();
+
+ private final IDozeHardware mHardware;
+
+ DozeHardware(IDozeHardware hardware) {
+ mHardware = hardware;
+ }
+
+ /**
+ * Sets whether to enable the microcontroller.
+ *
+ * @param enable If true, enables the MCU otherwise disables it.
+ */
+ public void setEnableMcu(boolean enable) {
+ sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF);
+ }
+
+ /**
+ * Sends a message to the doze hardware module.
+ *
+ * @param msg The name of the message to send.
+ * @param arg An optional argument data blob, may be null.
+ * @return A result data blob, may be null.
+ */
+ public byte[] sendMessage(String msg, byte[] arg) {
+ if (msg == null) {
+ throw new IllegalArgumentException("msg must not be null");
+ }
+
+ try {
+ return mHardware.sendMessage(msg, arg);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to send message to doze hardware module.", ex);
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 17ea996..9f7ddba 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -25,7 +25,7 @@
/**
* Called by the power manager to start a dream.
*/
- public abstract void startDream();
+ public abstract void startDream(boolean doze);
/**
* Called by the power manager to stop a dream.
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index f6b6c89..1abb1d7 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -20,12 +20,14 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.AlarmManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.ActionMode;
@@ -42,6 +44,8 @@
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
/**
* Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -145,19 +149,26 @@
*/
public static final String DREAM_META_DATA = "android.service.dream";
+ private final IDreamManager mSandman;
private final Handler mHandler = new Handler();
private IBinder mWindowToken;
private Window mWindow;
private WindowManager mWindowManager;
- private IDreamManager mSandman;
private boolean mInteractive = false;
private boolean mLowProfile = true;
private boolean mFullscreen = false;
private boolean mScreenBright = true;
private boolean mFinished;
+ private boolean mCanDoze;
+ private boolean mDozing;
+ private DozeHardware mDozeHardware;
private boolean mDebug = false;
+ public DreamService() {
+ mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
+ }
+
/**
* @hide
*/
@@ -444,9 +455,11 @@
* correct interactions with it (seeing when it is cleared etc).
*/
public void setLowProfile(boolean lowProfile) {
- mLowProfile = lowProfile;
- int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
- applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+ if (mLowProfile != lowProfile) {
+ mLowProfile = lowProfile;
+ int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+ applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+ }
}
/**
@@ -467,9 +480,11 @@
* will be cleared.
*/
public void setFullscreen(boolean fullscreen) {
- mFullscreen = fullscreen;
- int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
- applyWindowFlags(mFullscreen ? flag : 0, flag);
+ if (mFullscreen != fullscreen) {
+ mFullscreen = fullscreen;
+ int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ applyWindowFlags(mFullscreen ? flag : 0, flag);
+ }
}
/**
@@ -487,14 +502,16 @@
* @param screenBright True to keep the screen bright while dreaming.
*/
public void setScreenBright(boolean screenBright) {
- mScreenBright = screenBright;
- int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
- applyWindowFlags(mScreenBright ? flag : 0, flag);
+ if (mScreenBright != screenBright) {
+ mScreenBright = screenBright;
+ int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ applyWindowFlags(mScreenBright ? flag : 0, flag);
+ }
}
/**
- * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false,
- * allowing the screen to dim if necessary.
+ * Returns whether or not this dream keeps the screen bright while dreaming.
+ * Defaults to false, allowing the screen to dim if necessary.
*
* @see #setScreenBright(boolean)
*/
@@ -503,6 +520,119 @@
}
/**
+ * Returns true if this dream is allowed to doze.
+ * <p>
+ * The value returned by this method is only meaningful when the dream has started.
+ * </p>
+ *
+ * @return True if this dream can doze.
+ * @see #startDozing
+ * @hide experimental
+ */
+ public boolean canDoze() {
+ return mCanDoze;
+ }
+
+ /**
+ * Starts dozing, entering a deep dreamy sleep.
+ * <p>
+ * Dozing enables the system to conserve power while the user is not actively interacting
+ * with the device. While dozing, the display will remain on in a low-power state
+ * and will continue to show its previous contents but the application processor and
+ * other system components will be allowed to suspend when possible.
+ * </p><p>
+ * While the application processor is suspended, the dream may stop executing code
+ * for long periods of time. Prior to being suspended, the dream may schedule periodic
+ * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
+ * The dream may also keep the CPU awake by acquiring a
+ * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
+ * Note that since the purpose of doze mode is to conserve power (especially when
+ * running on battery), the dream should not wake the CPU very often or keep it
+ * awake for very long.
+ * </p><p>
+ * It is a good idea to call this method some time after the dream's entry animation
+ * has completed and the dream is ready to doze. It is important to completely
+ * finish all of the work needed before dozing since the application processor may
+ * be suspended at any moment once this method is called unless other wake locks
+ * are being held.
+ * </p><p>
+ * Call {@link #stopDozing} or {@link #finish} to stop dozing.
+ * </p>
+ *
+ * @see #stopDozing
+ * @hide experimental
+ */
+ public void startDozing() {
+ if (mCanDoze && !mDozing) {
+ mDozing = true;
+ try {
+ mSandman.startDozing(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ }
+
+ /**
+ * Stops dozing, returns to active dreaming.
+ * <p>
+ * This method reverses the effect of {@link #startDozing}. From this moment onward,
+ * the application processor will be kept awake as long as the dream is running
+ * or until the dream starts dozing again.
+ * </p>
+ *
+ * @see #startDozing
+ * @hide experimental
+ */
+ public void stopDozing() {
+ if (mDozing) {
+ mDozing = false;
+ try {
+ mSandman.stopDozing(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ }
+
+ /**
+ * Returns true if the dream will allow the system to enter a low-power state while
+ * it is running without actually turning off the screen. Defaults to false,
+ * keeping the application processor awake while the dream is running.
+ *
+ * @return True if the dream is dozing.
+ *
+ * @see #setDozing(boolean)
+ * @hide experimental
+ */
+ public boolean isDozing() {
+ return mDozing;
+ }
+
+ /**
+ * Gets an object that may be used to access low-level hardware features that a
+ * dream may use to provide a richer user experience while dozing.
+ *
+ * @return An instance of {@link DozeHardware} or null if this device does not offer
+ * hardware support for dozing.
+ *
+ * @hide experimental
+ */
+ public DozeHardware getDozeHardware() {
+ if (mCanDoze && mDozeHardware == null) {
+ try {
+ IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
+ if (hardware != null) {
+ mDozeHardware = new DozeHardware(hardware);
+ }
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ return mDozeHardware;
+ }
+
+ /**
* Called when this Dream is constructed.
*/
@Override
@@ -536,7 +666,11 @@
}
/**
- * Stops the dream, detaches from the window, and wakes up.
+ * Stops the dream and detaches from the window.
+ * <p>
+ * When the dream ends, the system will be allowed to go to sleep fully unless there
+ * is a reason for it to be awake such as recent user activity or wake locks being held.
+ * </p>
*/
public final void finish() {
if (mDebug) Slog.v(TAG, "finish()");
@@ -557,10 +691,6 @@
// end public api
- private void loadSandman() {
- mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
- }
-
/**
* Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
*
@@ -572,23 +702,16 @@
return;
}
- try {
- onDreamingStopped();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStopped()", t);
- // we were going to stop anyway
- }
+ if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+ onDreamingStopped();
if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
- try {
- // force our window to be removed synchronously
- mWindowManager.removeViewImmediate(mWindow.getDecorView());
- // the following will print a log message if it finds any other leaked windows
- WindowManagerGlobal.getInstance().closeAll(mWindowToken,
- this.getClass().getName(), "Dream");
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed removing window view", t);
- }
+
+ // force our window to be removed synchronously
+ mWindowManager.removeViewImmediate(mWindow.getDecorView());
+ // the following will print a log message if it finds any other leaked windows
+ WindowManagerGlobal.getInstance().closeAll(mWindowToken,
+ this.getClass().getName(), "Dream");
mWindow = null;
mWindowToken = null;
@@ -601,23 +724,30 @@
*
* @param windowToken A window token that will allow a window to be created in the correct layer.
*/
- private final void attach(IBinder windowToken) {
+ private final void attach(IBinder windowToken, boolean canDoze) {
if (mWindowToken != null) {
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
return;
}
+ if (mFinished) {
+ Slog.w(TAG, "attach() called after dream already finished");
+ try {
+ mSandman.finishSelf(windowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ return;
+ }
if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
- if (mSandman == null) {
- loadSandman();
- }
mWindowToken = windowToken;
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE);
+ mCanDoze = canDoze;
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -642,40 +772,25 @@
mWindowManager = mWindow.getWindowManager();
if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
- try {
- applySystemUiVisibilityFlags(
- (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
- View.SYSTEM_UI_FLAG_LOW_PROFILE);
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed adding window view", t);
- safelyFinish();
- return;
- }
+ applySystemUiVisibilityFlags(
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
// start it up
mHandler.post(new Runnable() {
@Override
public void run() {
- try {
- onDreamingStarted();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStarted()", t);
- safelyFinish();
- }
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ onDreamingStarted();
}
});
}
private void safelyFinish() {
if (mDebug) Slog.v(TAG, "safelyFinish()");
- try {
- finish();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in safelyFinish()", t);
- finishInternal();
- return;
- }
+
+ finish();
if (!mFinished) {
Slog.w(TAG, "Bad dream, did not call super.finish()");
@@ -685,19 +800,21 @@
private void finishInternal() {
if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
- if (mFinished) return;
- try {
+
+ if (!mFinished) {
mFinished = true;
- if (mSandman != null) {
- mSandman.finishSelf(mWindowToken);
+ if (mWindowToken == null) {
+ Slog.w(TAG, "Finish was called before the dream was attached.");
} else {
- Slog.w(TAG, "No dream manager found");
+ try {
+ mSandman.finishSelf(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
}
- stopSelf(); // if launched via any other means
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in finishInternal()", t);
+ stopSelf(); // if launched via any other means
}
}
@@ -732,32 +849,39 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- super.dump(fd, pw, args);
-
- pw.print(TAG + ": ");
- if (mWindowToken == null) {
- pw.println("stopped");
- } else {
- pw.println("running (token=" + mWindowToken + ")");
- }
- pw.println(" window: " + mWindow);
- pw.print(" flags:");
- if (isInteractive()) pw.print(" interactive");
- if (isLowProfile()) pw.print(" lowprofile");
- if (isFullscreen()) pw.print(" fullscreen");
- if (isScreenBright()) pw.print(" bright");
- pw.println();
+ DumpUtils.dumpAsync(mHandler, new Dump() {
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.print(TAG + ": ");
+ if (mWindowToken == null) {
+ pw.println("stopped");
+ } else {
+ pw.println("running (token=" + mWindowToken + ")");
+ }
+ pw.println(" window: " + mWindow);
+ pw.print(" flags:");
+ if (isInteractive()) pw.print(" interactive");
+ if (isLowProfile()) pw.print(" lowprofile");
+ if (isFullscreen()) pw.print(" fullscreen");
+ if (isScreenBright()) pw.print(" bright");
+ if (isDozing()) pw.print(" dozing");
+ pw.println();
+ }
+ }, pw, 1000);
}
- private class DreamServiceWrapper extends IDreamService.Stub {
- public void attach(final IBinder windowToken) {
+ private final class DreamServiceWrapper extends IDreamService.Stub {
+ @Override
+ public void attach(final IBinder windowToken, final boolean canDoze) {
mHandler.post(new Runnable() {
@Override
public void run() {
- DreamService.this.attach(windowToken);
+ DreamService.this.attach(windowToken, canDoze);
}
});
}
+
+ @Override
public void detach() {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/service/dreams/IDozeHardware.aidl
new file mode 100644
index 0000000..f5a657b
--- /dev/null
+++ b/core/java/android/service/dreams/IDozeHardware.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.service.dreams;
+
+/**
+ * @hide
+ */
+interface IDozeHardware {
+ byte[] sendMessage(String msg, in byte[] arg);
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 1c1b390..2718e316 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -16,10 +16,11 @@
package android.service.dreams;
+import android.content.ComponentName;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
-import android.content.ComponentName;
import android.os.IBinder;
+import android.service.dreams.IDozeHardware;
/** @hide */
interface IDreamManager {
@@ -31,4 +32,7 @@
void testDream(in ComponentName componentName);
boolean isDreaming();
void finishSelf(in IBinder token);
+ void startDozing(in IBinder token);
+ void stopDozing(in IBinder token);
+ IDozeHardware getDozeHardware(in IBinder token);
}
\ No newline at end of file
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
index 99dc0b7..bd58f1d 100644
--- a/core/java/android/service/dreams/IDreamService.aidl
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -20,6 +20,6 @@
* @hide
*/
oneway interface IDreamService {
- void attach(IBinder windowToken);
+ void attach(IBinder windowToken, boolean canDoze);
void detach();
}
diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java
index dd504c1..4015488 100644
--- a/core/java/android/util/LruCache.java
+++ b/core/java/android/util/LruCache.java
@@ -87,9 +87,8 @@
/**
* Sets the size of the cache.
- * @param maxSize The new maximum size.
*
- * @hide
+ * @param maxSize The new maximum size.
*/
public void resize(int maxSize) {
if (maxSize <= 0) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 2ed0cba..a08d83a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -351,11 +351,11 @@
// Atlas
///////////////////////////////////////////////////////////////////////////
- static void initAtlas(GraphicBuffer buffer, int[] map) {
+ static void initAtlas(GraphicBuffer buffer, long[] map) {
nInitAtlas(buffer, map, map.length);
}
- private static native void nInitAtlas(GraphicBuffer buffer, int[] map, int count);
+ private static native void nInitAtlas(GraphicBuffer buffer, long[] map, int count);
///////////////////////////////////////////////////////////////////////////
// Display list
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index d61c4b1..b758930 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -271,7 +271,7 @@
if (atlas.isCompatible(android.os.Process.myPpid())) {
GraphicBuffer buffer = atlas.getBuffer();
if (buffer != null) {
- int[] map = atlas.getMap();
+ long[] map = atlas.getMap();
if (map != null) {
GLES20Canvas.initAtlas(buffer, map);
}
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 958c071..8900d23 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -66,8 +66,7 @@
* @see View#setLayerPaint(android.graphics.Paint)
*/
public void setLayerPaint(Paint paint) {
- nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint,
- paint.getColorFilter() != null ? paint.getColorFilter().native_instance : 0);
+ nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint);
}
/**
@@ -270,7 +269,7 @@
private static native void nDestroyLayerUpdater(long layerUpdater);
private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
- private static native void nSetLayerPaint(long layerUpdater, long paint, long colorFilter);
+ private static native void nSetLayerPaint(long layerUpdater, long paint);
private static native void nSetTransform(long layerUpdater, long matrix);
private static native void nSetSurfaceTexture(long layerUpdater,
SurfaceTexture surface, boolean isAlreadyAttached);
diff --git a/core/java/android/view/IAssetAtlas.aidl b/core/java/android/view/IAssetAtlas.aidl
index 5f1e238..edce059 100644
--- a/core/java/android/view/IAssetAtlas.aidl
+++ b/core/java/android/view/IAssetAtlas.aidl
@@ -45,10 +45,10 @@
* if the atlas is not available yet.
*
* Each bitmap is represented by several entries in the array:
- * int0: SkBitmap*, the native bitmap object
- * int1: x position
- * int2: y position
- * int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
+ * long0: SkBitmap*, the native bitmap object
+ * long1: x position
+ * long2: y position
+ * long3: rotated, 1 if the bitmap must be rotated, 0 otherwise
*/
- int[] getMap();
+ long[] getMap();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index af62d9c..e30f825 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11447,76 +11447,54 @@
(!(mParent instanceof ViewGroup) ||
!((ViewGroup) mParent).isViewTransitioning(this));
}
+
/**
* Mark the area defined by dirty as needing to be drawn. If the view is
- * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some point
- * in the future. This must be called from a UI thread. To call from a non-UI
- * thread, call {@link #postInvalidate()}.
+ * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some
+ * point in the future.
+ * <p>
+ * This must be called from a UI thread. To call from a non-UI thread, call
+ * {@link #postInvalidate()}.
+ * <p>
+ * <b>WARNING:</b> In API 19 and below, this method may be destructive to
+ * {@code dirty}.
*
- * WARNING: This method is destructive to dirty.
* @param dirty the rectangle representing the bounds of the dirty region
*/
public void invalidate(Rect dirty) {
- if (skipInvalidate()) {
- return;
- }
- if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
- (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID ||
- (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) {
- mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags |= PFLAG_INVALIDATED;
- mPrivateFlags |= PFLAG_DIRTY;
- final ViewParent p = mParent;
- final AttachInfo ai = mAttachInfo;
- if (p != null && ai != null) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
- final Rect r = ai.mTmpInvalRect;
- r.set(dirty.left - scrollX, dirty.top - scrollY,
- dirty.right - scrollX, dirty.bottom - scrollY);
- mParent.invalidateChild(this, r);
- }
- }
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
+ invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
+ dirty.right - scrollX, dirty.bottom - scrollY, true);
}
/**
- * Mark the area defined by the rect (l,t,r,b) as needing to be drawn.
- * The coordinates of the dirty rect are relative to the view.
- * If the view is visible, {@link #onDraw(android.graphics.Canvas)}
- * will be called at some point in the future. This must be called from
- * a UI thread. To call from a non-UI thread, call {@link #postInvalidate()}.
+ * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The
+ * coordinates of the dirty rect are relative to the view. If the view is
+ * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some
+ * point in the future.
+ * <p>
+ * This must be called from a UI thread. To call from a non-UI thread, call
+ * {@link #postInvalidate()}.
+ *
* @param l the left position of the dirty region
* @param t the top position of the dirty region
* @param r the right position of the dirty region
* @param b the bottom position of the dirty region
*/
public void invalidate(int l, int t, int r, int b) {
- if (skipInvalidate()) {
- return;
- }
- if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
- (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID ||
- (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) {
- mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags |= PFLAG_INVALIDATED;
- mPrivateFlags |= PFLAG_DIRTY;
- final ViewParent p = mParent;
- final AttachInfo ai = mAttachInfo;
- if (p != null && ai != null && l < r && t < b) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
- final Rect tmpr = ai.mTmpInvalRect;
- tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY);
- p.invalidateChild(this, tmpr);
- }
- }
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
+ invalidateInternal(l - scrollX, t - scrollY, r - scrollY, b - scrollY, true);
}
/**
* Invalidate the whole view. If the view is visible,
* {@link #onDraw(android.graphics.Canvas)} will be called at some point in
- * the future. This must be called from a UI thread. To call from a non-UI thread,
- * call {@link #postInvalidate()}.
+ * the future.
+ * <p>
+ * This must be called from a UI thread. To call from a non-UI thread, call
+ * {@link #postInvalidate()}.
*/
public void invalidate() {
invalidate(true);
@@ -11524,43 +11502,83 @@
/**
* This is where the invalidate() work actually happens. A full invalidate()
- * causes the drawing cache to be invalidated, but this function can be called with
- * invalidateCache set to false to skip that invalidation step for cases that do not
- * need it (for example, a component that remains at the same dimensions with the same
- * content).
+ * causes the drawing cache to be invalidated, but this function can be
+ * called with invalidateCache set to false to skip that invalidation step
+ * for cases that do not need it (for example, a component that remains at
+ * the same dimensions with the same content).
*
- * @param invalidateCache Whether the drawing cache for this view should be invalidated as
- * well. This is usually true for a full invalidate, but may be set to false if the
- * View's contents or dimensions have not changed.
+ * @param invalidateCache Whether the drawing cache for this view should be
+ * invalidated as well. This is usually true for a full
+ * invalidate, but may be set to false if the View's contents or
+ * dimensions have not changed.
*/
void invalidate(boolean invalidateCache) {
+ invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache);
+ }
+
+ void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache) {
if (skipInvalidate()) {
return;
}
- if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
- (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||
- (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {
+
+ final boolean wasDrawn = (mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS))
+ == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS);
+ final boolean hasValidCache = (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0;
+ final boolean invalidated = (mPrivateFlags & PFLAG_INVALIDATED) != 0;
+ final boolean opacityChanged = isOpaque() != mLastIsOpaque;
+ if (wasDrawn || (invalidateCache && hasValidCache) || !invalidated || opacityChanged) {
mLastIsOpaque = isOpaque();
mPrivateFlags &= ~PFLAG_DRAWN;
mPrivateFlags |= PFLAG_DIRTY;
+
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
+
+ // Propagate the damage rectangle to the parent view.
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
+ if (p != null && ai != null && l < r && t < b) {
+ final Rect damage = ai.mTmpInvalRect;
+ damage.set(l, t, r, b);
+ p.invalidateChild(this, damage);
+ }
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- // Don't call invalidate -- we don't want to internally scroll
- // our own bounds
- p.invalidateChild(this, r);
+ // Damage the entire projection receiver, if necessary.
+ if (mBackground != null && mBackground.isProjected()) {
+ final View receiver = getProjectionReceiver();
+ if (receiver != null) {
+ receiver.damageInParent();
+ }
}
}
}
/**
+ * @return this view's projection receiver, or {@code null} if none exists
+ */
+ private View getProjectionReceiver() {
+ ViewParent p = getParent();
+ while (p != null && p instanceof View) {
+ final View v = (View) p;
+ if (v.isProjectionReceiver()) {
+ return v;
+ }
+ p = p.getParent();
+ }
+
+ return null;
+ }
+
+ /**
+ * @return whether the view is a projection receiver
+ */
+ private boolean isProjectionReceiver() {
+ return mBackground != null;
+ }
+
+ /**
* Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to
* set any flags or handle all of the cases handled by the default invalidation methods.
* Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate
@@ -11586,16 +11604,23 @@
}
invalidate(false);
} else {
- final AttachInfo ai = mAttachInfo;
- final ViewParent p = mParent;
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).invalidateChildFast(this, r);
- } else {
- mParent.invalidateChild(this, r);
- }
+ damageInParent();
+ }
+ }
+
+ /**
+ * Tells the parent view to damage this view's bounds.
+ */
+ private void damageInParent() {
+ final AttachInfo ai = mAttachInfo;
+ final ViewParent p = mParent;
+ if (p != null && ai != null) {
+ final Rect r = ai.mTmpInvalRect;
+ r.set(0, 0, mRight - mLeft, mBottom - mTop);
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).invalidateChildFast(this, r);
+ } else {
+ mParent.invalidateChild(this, r);
}
}
}
@@ -12468,7 +12493,7 @@
}
/**
- * <p>Compute the vertical extent of the horizontal scrollbar's thumb
+ * <p>Compute the vertical extent of the vertical scrollbar's thumb
* within the vertical range. This value is used to compute the length
* of the thumb within the scrollbar's track.</p>
*
@@ -15635,11 +15660,6 @@
@Override
public void invalidateDrawable(Drawable drawable) {
if (verifyDrawable(drawable)) {
- if (drawable == mBackground && mBackgroundDisplayList != null) {
- // We'll need to redraw the display list.
- mBackgroundDisplayList.clear();
- }
-
final Rect dirty = drawable.getDirtyBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index d9e140e..75656545 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -119,20 +119,6 @@
public final static int ACTION_PASS_TO_USER = 0x00000001;
/**
- * This key event should wake the device.
- * To be returned from {@link #interceptKeyBeforeQueueing}.
- * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}.
- */
- public final static int ACTION_WAKE_UP = 0x00000002;
-
- /**
- * This key event should put the device to sleep (and engage keyguard if necessary)
- * To be returned from {@link #interceptKeyBeforeQueueing}.
- * Do not return this and {@link #ACTION_WAKE_UP} or {@link #ACTION_PASS_TO_USER}.
- */
- public final static int ACTION_GO_TO_SLEEP = 0x00000004;
-
- /**
* Interface to the Window Manager state associated with a particular
* window. You can hold on to an instance of this interface from the call
* to prepareAddWindow() until removeWindow().
@@ -760,8 +746,7 @@
* @param policyFlags The policy flags associated with the key.
* @param isScreenOn True if the screen is already on
*
- * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
- * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+ * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
@@ -774,10 +759,9 @@
* because it's the most fragile.
* @param policyFlags The policy flags associated with the motion.
*
- * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
- * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+ * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(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/AdapterView.java b/core/java/android/widget/AdapterView.java
index 962ffba..1da22ca 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -667,7 +667,7 @@
/**
* When the current adapter is empty, the AdapterView can display a special view
- * call the empty view. The empty view is used to provide feedback to the user
+ * called the empty view. The empty view is used to provide feedback to the user
* that no data is available in this AdapterView.
*
* @return The view to show if the adapter is empty.
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index d8041c5..5056c57 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -136,7 +136,6 @@
android_hardware_UsbDevice.cpp \
android_hardware_UsbDeviceConnection.cpp \
android_hardware_UsbRequest.cpp \
- android_debug_JNITest.cpp \
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
android/opengl/util.cpp.arm \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 100f71d..5bde80d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -133,7 +133,6 @@
extern int register_android_database_SQLiteConnection(JNIEnv* env);
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
extern int register_android_database_SQLiteDebug(JNIEnv* env);
-extern int register_android_debug_JNITest(JNIEnv* env);
extern int register_android_nio_utils(JNIEnv* env);
extern int register_android_text_format_Time(JNIEnv* env);
extern int register_android_os_Debug(JNIEnv* env);
@@ -1095,7 +1094,6 @@
}
static const RegJNIRec gRegJNI[] = {
- REG_JNI(register_android_debug_JNITest),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
diff --git a/core/jni/android_debug_JNITest.cpp b/core/jni/android_debug_JNITest.cpp
deleted file mode 100644
index 9147284..0000000
--- a/core/jni/android_debug_JNITest.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/* //device/libs/android_runtime/android_debug_JNITest.cpp
-**
-** Copyright 2006, 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.
-*/
-
-#define LOG_TAG "DebugJNI"
-
-#include "jni.h"
-#include "nativehelper/JNIHelp.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-//#include "android_runtime/AndroidRuntime.h"
-
-namespace android {
-
-/*
- * Implements:
- * native int part1(int intArg, double doubleArg, String stringArg,
- * int[] arrayArg)
- */
-static jint android_debug_JNITest_part1(JNIEnv* env, jobject object,
- jint intArg, jdouble doubleArg, jstring stringArg, jobjectArray arrayArg)
-{
- jclass clazz;
- jmethodID part2id;
- jsize arrayLen;
- jint arrayVal;
- int result = -2;
-
- ALOGI("JNI test: in part1, intArg=%d, doubleArg=%.3f\n", intArg, doubleArg);
-
- /* find "int part2(double doubleArg, int fromArray, String stringArg)" */
- clazz = env->GetObjectClass(object);
- part2id = env->GetMethodID(clazz,
- "part2", "(DILjava/lang/String;)I");
- if (part2id == NULL) {
- ALOGE("JNI test: unable to find part2\n");
- return -1;
- }
-
- /* get the length of the array */
- arrayLen = env->GetArrayLength(arrayArg);
- ALOGI(" array size is %d\n", arrayLen);
-
- /*
- * Get the last element in the array.
- * Use the Get<type>ArrayElements functions instead if you need access
- * to multiple elements.
- */
- arrayVal = (int) env->GetObjectArrayElement(arrayArg, arrayLen-1);
- ALOGI(" array val is %d\n", arrayVal);
-
- /* call this->part2 */
- result = env->CallIntMethod(object, part2id,
- doubleArg, arrayVal, stringArg);
-
- return result;
-}
-
-/*
- * Implements:
- * private static native int part3(String stringArg);
- */
-static jint android_debug_JNITest_part3(JNIEnv* env, jclass clazz,
- jstring stringArg)
-{
- const char* utfChars;
- jboolean isCopy;
-
- ALOGI("JNI test: in part3\n");
-
- utfChars = env->GetStringUTFChars(stringArg, &isCopy);
-
- ALOGI(" String is '%s', isCopy=%d\n", (const char*) utfChars, isCopy);
-
- env->ReleaseStringUTFChars(stringArg, utfChars);
-
- return 2000;
-}
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "part1", "(IDLjava/lang/String;[I)I",
- (void*) android_debug_JNITest_part1 },
- { "part3", "(Ljava/lang/String;)I",
- (void*) android_debug_JNITest_part3 },
-};
-int register_android_debug_JNITest(JNIEnv* env)
-{
- return jniRegisterNativeMethods(env, "android/debug/JNITest",
- gMethods, NELEM(gMethods));
-}
-
-#if 0
-/* trampoline into C++ */
-extern "C"
-int register_android_debug_JNITest_C(JNIEnv* env)
-{
- return android::register_android_debug_JNITest(env);
-}
-#endif
-
-}; // namespace android
-
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index dd089f2..4e353fa 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -116,14 +116,12 @@
// ----------------------------------------------------------------------------
static void android_view_GLES20Canvas_initAtlas(JNIEnv* env, jobject clazz,
- jobject graphicBuffer, jintArray atlasMapArray, jint count) {
+ jobject graphicBuffer, jlongArray atlasMapArray, jint count) {
sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
- jint* atlasMap = env->GetIntArrayElements(atlasMapArray, NULL);
-
- Caches::getInstance().assetAtlas.init(buffer, atlasMap, count);
-
- env->ReleaseIntArrayElements(atlasMapArray, atlasMap, 0);
+ jlong* jAtlasMap = env->GetLongArrayElements(atlasMapArray, NULL);
+ Caches::getInstance().assetAtlas.init(buffer, jAtlasMap, count);
+ env->ReleaseLongArrayElements(atlasMapArray, jAtlasMap, 0);
}
// ----------------------------------------------------------------------------
@@ -1002,7 +1000,7 @@
{ "nInitCaches", "()Z", (void*) android_view_GLES20Canvas_initCaches },
{ "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches },
- { "nInitAtlas", "(Landroid/view/GraphicBuffer;[II)V",
+ { "nInitAtlas", "(Landroid/view/GraphicBuffer;[JI)V",
(void*) android_view_GLES20Canvas_initAtlas },
{ "nCreateRenderer", "()J", (void*) android_view_GLES20Canvas_createRenderer },
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 8a0a011..5b21e94 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -88,13 +88,11 @@
}
static void android_view_HardwareLayer_setLayerPaint(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr, jlong paintPtr, jlong colorFilterPtr) {
+ jlong layerUpdaterPtr, jlong paintPtr) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
if (layer) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
- SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
layer->setPaint(paint);
- layer->setColorFilter(colorFilter);
}
}
@@ -162,7 +160,7 @@
{ "nDestroyLayerUpdater", "(J)V", (void*) android_view_HardwareLayer_destroyLayerUpdater },
{ "nPrepare", "(JIIZ)Z", (void*) android_view_HardwareLayer_prepare },
- { "nSetLayerPaint", "(JJJ)V", (void*) android_view_HardwareLayer_setLayerPaint },
+ { "nSetLayerPaint", "(JJ)V", (void*) android_view_HardwareLayer_setLayerPaint },
{ "nSetTransform", "(JJ)V", (void*) android_view_HardwareLayer_setTransform },
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
(void*) android_view_HardwareLayer_setSurfaceTexture },
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b1b1f42..519e2ae 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -658,6 +658,11 @@
Must be in the range specified by minimum and maximum. -->
<integer name="config_screenBrightnessSettingDefault">102</integer>
+ <!-- Screen brightness used to dim the screen while dozing in a very low power state.
+ May be less than the minimum allowed brightness setting
+ that can be set by the user. -->
+ <integer name="config_screenBrightnessDoze">1</integer>
+
<!-- Screen brightness used to dim the screen when the user activity
timeout expires. May be less than the minimum allowed brightness setting
that can be set by the user. -->
@@ -1089,6 +1094,70 @@
<!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
<string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+ <!-- Are we allowed to dream while not plugged in? -->
+ <bool name="config_dreamsEnabledOnBattery">false</bool>
+ <!-- Minimum battery level to allow dreaming when powered.
+ Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelMinimumWhenPowered">-1</integer>
+ <!-- Minimum battery level to allow dreaming when not powered.
+ Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelMinimumWhenNotPowered">15</integer>
+ <!-- If the battery level drops by this percentage and the user activity timeout
+ has expired, then assume the device is receiving insufficient current to charge
+ effectively and terminate the dream. Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
+
+ <!-- ComponentName of a dream to show whenever the system would otherwise have
+ gone to sleep. When the PowerManager is asked to go to sleep, it will instead
+ try to start this dream if possible. The dream should typically call startDozing()
+ to put the display into a low power state and allow the application processor
+ to be suspended. When the dream ends, the system will go to sleep as usual.
+ Specify the component name (Settings.Secure.SCREENSAVER_COMPONENT) or an
+ empty string if none.
+
+ Note that doze dreams are not subject to the same start conditions as ordinary dreams.
+ Doze dreams will run whenever the power manager is in a dozing state. -->
+ <string name="config_dozeComponent"></string>
+
+ <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
+ device from the display on/off state.
+
+ When false, autosuspend_disable() will be called before the display is turned on
+ and autosuspend_enable() will be called after the display is turned off.
+ This mode provides best compatibility for devices using legacy power management
+ features such as early suspend / late resume.
+
+ When true, autosuspend_display() and autosuspend_enable() will be called
+ independently of whether the display is being turned on or off. This mode
+ enables the power manager to suspend the application processor while the
+ display is on.
+
+ This resource should be set to "true" when a doze component has been specified
+ to maximize power savings but not all devices support it.
+
+ Refer to autosuspend.h for details.
+ -->
+ <bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>
+
+ <!-- Power Management: Specifies whether to decouple the interactive state of the
+ device from the display on/off state.
+
+ When false, setInteractive(..., true) will be called before the display is turned on
+ and setInteractive(..., false) will be called after the display is turned off.
+ This mode provides best compatibility for devices that expect the interactive
+ state to be tied to the display state.
+
+ When true, setInteractive(...) will be called independently of whether the display
+ is being turned on or off. This mode enables the power manager to reduce
+ clocks and disable the touch controller while the display is on.
+
+ This resource should be set to "true" when a doze component has been specified
+ to maximize power savings but not all devices support it.
+
+ Refer to power.h for details.
+ -->
+ <bool name="config_powerDecoupleInteractiveModeFromDisplay">false</bool>
+
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e574e8d..b1bf781 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1500,6 +1500,7 @@
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
<java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
+ <java-symbol type="integer" name="config_screenBrightnessDoze" />
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
<java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
@@ -1604,11 +1605,18 @@
<java-symbol type="xml" name="storage_list" />
<java-symbol type="bool" name="config_dreamsSupported" />
<java-symbol type="bool" name="config_dreamsEnabledByDefault" />
+ <java-symbol type="bool" name="config_dreamsEnabledOnBattery" />
<java-symbol type="bool" name="config_dreamsActivatedOnDockByDefault" />
<java-symbol type="bool" name="config_dreamsActivatedOnSleepByDefault" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenPowered" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenNotPowered" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelDrainCutoff" />
<java-symbol type="string" name="config_dreamsDefaultComponent" />
+ <java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
<java-symbol type="string" name="enable_explore_by_touch_warning_message" />
+ <java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" />
+ <java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index bd1edc2..b648d48 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -580,7 +580,7 @@
<a href="#nm"><code>android:name</code></a> attribute.
<p>The system reads this attribute to determine which activity should be started when
- the use presses the Up button in the action bar. The system can also use this information to
+ the user presses the Up button in the action bar. The system can also use this information to
synthesize a back stack of activities with {@link android.app.TaskStackBuilder}.</p>
<p>To support API levels 4 - 16, you can also declare the parent activity with a {@code
diff --git a/docs/html/tools/testing/testing_ui.jd b/docs/html/tools/testing/testing_ui.jd
index 701415e..4318a21 100644
--- a/docs/html/tools/testing/testing_ui.jd
+++ b/docs/html/tools/testing/testing_ui.jd
@@ -90,7 +90,7 @@
alt="User interface of uiautomatorviewer tool" height="327px" id="figure1"/>
</a>
<p class="img-caption">
- <strong>Figure 1.</strong> The {@code uiautomatorviewer} showing the captured interface of a test deviice.
+ <strong>Figure 1.</strong> The {@code uiautomatorviewer} showing the captured interface of a test device.
</p>
<p>To analyze the UI components of the application that you want to test:</p>
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index cbe20dc..618afb8 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -32,10 +32,10 @@
private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator(2.0f);
/** Starting radius for a ripple. */
- private static final int STARTING_RADIUS_DP = 40;
+ private static final int STARTING_RADIUS_DP = 16;
/** Radius when finger is outside view bounds. */
- private static final int OUTSIDE_RADIUS_DP = 40;
+ private static final int OUTSIDE_RADIUS_DP = 16;
/** Margin when constraining outside touches (fraction of outer radius). */
private static final float OUTSIDE_MARGIN = 0.8f;
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index f7cd9de..a21f1e0 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -25,7 +25,6 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.Xfermode;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -79,7 +78,7 @@
private Paint mRipplePaint;
/** Target density of the display into which ripples are drawn. */
- private int mTargetDensity;
+ private float mDensity = 1.0f;
/** Whether the animation runnable has been posted. */
private boolean mAnimating;
@@ -90,9 +89,7 @@
TouchFeedbackDrawable(TouchFeedbackState state, Resources res) {
if (res != null) {
- mTargetDensity = res.getDisplayMetrics().densityDpi;
- } else if (state != null) {
- mTargetDensity = state.mTargetDensity;
+ mDensity = res.getDisplayMetrics().density;
}
mState = state;
@@ -143,32 +140,30 @@
return mState.mColorStateList != null && mState.mColorStateList.isStateful();
}
- /**
- * Set the density at which this drawable will be rendered.
- *
- * @param density The density scale for this drawable.
- */
- public void setTargetDensity(int density) {
- if (mTargetDensity != density) {
- mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- // TODO: Update density in ripples?
- invalidateSelf();
- }
- }
-
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs);
- final TypedArray a = r.obtainAttributes(attrs,
- com.android.internal.R.styleable.ColorDrawable);
+ final TypedArray a = r.obtainAttributes(
+ attrs, com.android.internal.R.styleable.ColorDrawable);
mState.mColorStateList = a.getColorStateList(
com.android.internal.R.styleable.ColorDrawable_color);
a.recycle();
- mState.mXfermode = null; //new PorterDuffXfermode(Mode.SRC_ATOP);
- mState.mProjected = false;
+ setTargetDensity(r.getDisplayMetrics());
+ }
+
+ /**
+ * Set the density at which this drawable will be rendered.
+ *
+ * @param metrics The display metrics for this drawable.
+ */
+ private void setTargetDensity(DisplayMetrics metrics) {
+ if (mDensity != metrics.density) {
+ mDensity = metrics.density;
+ invalidateSelf();
+ }
}
/**
@@ -196,12 +191,13 @@
final Rect bounds = getBounds();
final Ripple newRipple = new Ripple(bounds, padding, bounds.exactCenterX(),
- bounds.exactCenterY(), mTargetDensity);
+ bounds.exactCenterY(), mDensity);
newRipple.enter();
mActiveRipples.add(newRipple);
mTouchedRipples.put(id, newRipple);
} else {
+ // TODO: How do we want to respond to movement?
//ripple.move(x, y);
}
@@ -296,7 +292,6 @@
mRipplePaint.setAntiAlias(true);
}
- mRipplePaint.setXfermode(mState.mXfermode);
mRipplePaint.setColor(color);
final int restoreCount = canvas.save();
@@ -345,16 +340,10 @@
static class TouchFeedbackState extends ConstantState {
ColorStateList mColorStateList;
- Xfermode mXfermode;
- int mTargetDensity;
- boolean mProjected;
public TouchFeedbackState(TouchFeedbackState orig) {
if (orig != null) {
mColorStateList = orig.mColorStateList;
- mXfermode = orig.mXfermode;
- mTargetDensity = orig.mTargetDensity;
- mProjected = orig.mProjected;
}
}
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index fddfe90..fc86e4f 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -28,7 +28,7 @@
// Lifecycle
///////////////////////////////////////////////////////////////////////////////
-void AssetAtlas::init(sp<GraphicBuffer> buffer, int* map, int count) {
+void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) {
if (mImage) {
return;
}
@@ -108,14 +108,19 @@
/**
* TODO: This method does not take the rotation flag into account
*/
-void AssetAtlas::createEntries(Caches& caches, int* map, int count) {
+void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) {
const float width = float(mTexture->width);
const float height = float(mTexture->height);
for (int i = 0; i < count; ) {
- SkBitmap* bitmap = (SkBitmap*) map[i++];
- int x = map[i++];
- int y = map[i++];
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(map[i++]);
+ // NOTE: We're converting from 64 bit signed values to 32 bit
+ // signed values. This is guaranteed to be safe because the "x"
+ // and "y" coordinate values are guaranteed to be representable
+ // with 32 bits. The array is 64 bits wide so that it can carry
+ // pointers on 64 bit architectures.
+ const int x = static_cast<int>(map[i++]);
+ const int y = static_cast<int>(map[i++]);
bool rotated = map[i++] > 0;
// Bitmaps should never be null, we're just extra paranoid
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index 57c8a60..2ec556e 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -121,7 +121,7 @@
* initialized. To re-initialize the atlas, you must
* first call terminate().
*/
- ANDROID_API void init(sp<GraphicBuffer> buffer, int* map, int count);
+ ANDROID_API void init(sp<GraphicBuffer> buffer, int64_t* map, int count);
/**
* Destroys the atlas texture. This object can be
@@ -176,7 +176,7 @@
}
private:
- void createEntries(Caches& caches, int* map, int count);
+ void createEntries(Caches& caches, int64_t* map, int count);
Texture* mTexture;
Image* mImage;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index efb1298..62f6c76 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -34,21 +34,23 @@
mWidth = mLayer->layer.getWidth();
mHeight = mLayer->layer.getHeight();
mBlend = mLayer->isBlend();
- mColorFilter = mLayer->getColorFilter();
+ mColorFilter = SkSafeRef(mLayer->getColorFilter());
mAlpha = mLayer->getAlpha();
mMode = mLayer->getMode();
mDirtyRect.setEmpty();
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
- setColorFilter(NULL);
+ SkSafeUnref(mColorFilter);
if (mLayer) {
mCaches.resourceCache.decrementRefcount(mLayer);
}
delete mRenderer;
}
-void DeferredLayerUpdater::setColorFilter(SkColorFilter* colorFilter) {
+void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
+ OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
+ SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : NULL;
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 624db2c..65f225c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -75,11 +75,7 @@
ANDROID_API void setDisplayList(DisplayList* displayList,
int left, int top, int right, int bottom);
- ANDROID_API void setPaint(const SkPaint* paint) {
- OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
- }
-
- ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
+ ANDROID_API void setPaint(const SkPaint* paint);
ANDROID_API bool apply();
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 0589a02..b5a66f6 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1410,7 +1410,7 @@
DeferredDisplayList::kOpBatch_Text :
DeferredDisplayList::kOpBatch_ColorText;
- deferInfo.mergeId = (mergeid_t)mPaint->getColor();
+ deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor());
// don't merge decorated text - the decorations won't draw in order
bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 70eeb39..54ce64f 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -131,8 +131,9 @@
}
}
-void Layer::setPaint(SkPaint* paint) {
+void Layer::setPaint(const SkPaint* paint) {
OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+ setColorFilter((paint) ? paint->getColorFilter() : NULL);
}
void Layer::setColorFilter(SkColorFilter* filter) {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index ec80e9c..8cc027a 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -117,7 +117,7 @@
texture.height = height;
}
- ANDROID_API void setPaint(SkPaint* paint);
+ ANDROID_API void setPaint(const SkPaint* paint);
inline void setBlend(bool blend) {
texture.blend = blend;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 9b253a6..2da0fd3 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -868,14 +868,11 @@
const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
- SkXfermode::Mode mode = getXfermodeDirect(paint);
- int alpha = getAlphaDirect(paint);
-
// Window coordinates of the layer
Rect clip;
Rect bounds(left, top, right, bottom);
calculateLayerBoundsAndClip(bounds, clip, fboLayer);
- updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha);
+ updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
// Bail out if we won't draw in this snapshot
if (currentSnapshot()->isIgnored()) {
@@ -888,12 +885,11 @@
return false;
}
- layer->setAlpha(alpha, mode);
+ layer->setPaint(paint);
layer->layer.set(bounds);
layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
bounds.getWidth() / float(layer->getWidth()), 0.0f);
- layer->setColorFilter(getColorFilter(paint));
layer->setBlend(true);
layer->setDirty(false);
@@ -1011,7 +1007,6 @@
}
if (!fboLayer && layer->getAlpha() < 255) {
- // TODO: this seems to point to the fact that the layer should store the paint
SkPaint layerPaint;
layerPaint.setAlpha(layer->getAlpha());
layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 36e89c6..5b642b9 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -151,7 +151,7 @@
mCaches.bindPixelBuffer(mBuffer);
unmap();
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
- GL_UNSIGNED_BYTE, (void*) offset);
+ GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ada649d..7886f5d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3799,14 +3799,11 @@
if (keyCode == KeyEvent.KEYCODE_POWER) {
policyFlags |= WindowManagerPolicy.FLAG_WAKE;
}
- final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
- | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
- + " policyFlags=" + Integer.toHexString(policyFlags)
- + " isWakeKey=" + isWakeKey);
+ + " policyFlags=" + Integer.toHexString(policyFlags));
}
if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
@@ -3823,6 +3820,8 @@
// the device some other way (which is why we have an exemption here for injected
// events).
int result;
+ boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
+ | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isScreenOn || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
@@ -3830,8 +3829,8 @@
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
result = 0;
- if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
- result |= ACTION_WAKE_UP;
+ if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
+ isWakeKey = false;
}
}
@@ -3941,7 +3940,8 @@
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ mPowerManager.goToSleep(event.getEventTime());
+ isWakeKey = false;
}
}
}
@@ -3988,7 +3988,8 @@
mPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ mPowerManager.goToSleep(event.getEventTime());
+ isWakeKey = false;
}
mPendingPowerKeyUpCanceled = false;
}
@@ -4058,6 +4059,10 @@
break;
}
}
+
+ if (isWakeKey) {
+ mPowerManager.wakeUp(event.getEventTime());
+ }
return result;
}
@@ -4098,13 +4103,13 @@
/** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
int result = 0;
final boolean isWakeMotion = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isWakeMotion) {
- result |= ACTION_WAKE_UP;
+ mPowerManager.wakeUp(whenNanos / 1000000);
}
return result;
}
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index 3fb006b..fc4838c 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -114,12 +114,11 @@
// Describes how bitmaps are placed in the atlas. Each bitmap is
// represented by several entries in the array:
- // int0: SkBitmap*, the native bitmap object
- // int1: x position
- // int2: y position
- // int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
- // NOTE: This will need to be handled differently to support 64 bit pointers
- private int[] mAtlasMap;
+ // long0: SkBitmap*, the native bitmap object
+ // long1: x position
+ // long2: y position
+ // long3: rotated, 1 if the bitmap must be rotated, 0 otherwise
+ private long[] mAtlasMap;
/**
* Creates a new service. Upon creating, the service will gather the list of
@@ -196,7 +195,7 @@
private final ArrayList<Bitmap> mBitmaps;
private final int mPixelCount;
- private int mNativeBitmap;
+ private long mNativeBitmap;
// Used for debugging only
private Bitmap mAtlasBitmap;
@@ -260,8 +259,8 @@
final Atlas.Entry entry = new Atlas.Entry();
- mAtlasMap = new int[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
- int[] atlasMap = mAtlasMap;
+ mAtlasMap = new long[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
+ long[] atlasMap = mAtlasMap;
int mapIndex = 0;
boolean result = false;
@@ -288,8 +287,7 @@
}
canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
canvas.restore();
- // TODO: Change mAtlasMap to long[] to support 64-bit systems
- atlasMap[mapIndex++] = (int) bitmap.mNativeBitmap;
+ atlasMap[mapIndex++] = bitmap.mNativeBitmap;
atlasMap[mapIndex++] = entry.x;
atlasMap[mapIndex++] = entry.y;
atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
@@ -365,9 +363,9 @@
}
}
- private static native int nAcquireAtlasCanvas(Canvas canvas, int width, int height);
- private static native void nReleaseAtlasCanvas(Canvas canvas, int bitmap);
- private static native boolean nUploadAtlas(GraphicBuffer buffer, int bitmap);
+ private static native long nAcquireAtlasCanvas(Canvas canvas, int width, int height);
+ private static native void nReleaseAtlasCanvas(Canvas canvas, long bitmap);
+ private static native boolean nUploadAtlas(GraphicBuffer buffer, long bitmap);
@Override
public boolean isCompatible(int ppid) {
@@ -380,7 +378,7 @@
}
@Override
- public int[] getMap() throws RemoteException {
+ public long[] getMap() throws RemoteException {
return mAtlasReady.get() ? mAtlasMap : null;
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index aa9849e..f587ccc 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -863,6 +863,7 @@
"User cannot modify accounts");
} catch (RemoteException re) {
}
+ return;
}
long identityToken = clearCallingIdentity();
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 77bb1a9..922cef4 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1235,12 +1235,14 @@
mUndrawnActivitiesBelowTopTranslucent.clear();
mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
- if (waitingActivity != null && waitingActivity.app != null &&
- waitingActivity.app.thread != null) {
- try {
- waitingActivity.app.thread.scheduleTranslucentConversionComplete(
- waitingActivity.appToken, r != null);
- } catch (RemoteException e) {
+ if (waitingActivity != null) {
+ mWindowManager.setWindowOpaque(waitingActivity.appToken, false);
+ if (waitingActivity.app != null && waitingActivity.app.thread != null) {
+ try {
+ waitingActivity.app.thread.scheduleTranslucentConversionComplete(
+ waitingActivity.appToken, r != null);
+ } catch (RemoteException e) {
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 207d630..ec500c2 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -1,3 +1,19 @@
+/*
+ * 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 com.android.server.am;
import java.io.File;
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 85ef33e..649b5c9 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -85,6 +85,7 @@
pw.println(" mToken=" + mCurrentDream.mToken);
pw.println(" mName=" + mCurrentDream.mName);
pw.println(" mIsTest=" + mCurrentDream.mIsTest);
+ pw.println(" mCanDoze=" + mCurrentDream.mCanDoze);
pw.println(" mUserId=" + mCurrentDream.mUserId);
pw.println(" mBound=" + mCurrentDream.mBound);
pw.println(" mService=" + mCurrentDream.mService);
@@ -94,15 +95,18 @@
}
}
- public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
+ public void startDream(Binder token, ComponentName name,
+ boolean isTest, boolean canDoze, int userId) {
stopDream();
// Close the notification shade. Don't need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
- Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
+ Slog.i(TAG, "Starting dream: name=" + name
+ + ", isTest=" + isTest + ", canDoze=" + canDoze
+ + ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, userId);
+ mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
try {
mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
@@ -140,7 +144,8 @@
final DreamRecord oldDream = mCurrentDream;
mCurrentDream = null;
Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
- + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+ + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ + ", userId=" + oldDream.mUserId);
mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
@@ -187,7 +192,7 @@
private void attach(IDreamService service) {
try {
service.asBinder().linkToDeath(mCurrentDream, 0);
- service.attach(mCurrentDream.mToken);
+ service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
} catch (RemoteException ex) {
Slog.e(TAG, "The dream service died unexpectedly.", ex);
stopDream();
@@ -213,6 +218,7 @@
public final Binder mToken;
public final ComponentName mName;
public final boolean mIsTest;
+ public final boolean mCanDoze;
public final int mUserId;
public boolean mBound;
@@ -221,10 +227,11 @@
public boolean mSentStartBroadcast;
public DreamRecord(Binder token, ComponentName name,
- boolean isTest, int userId) {
+ boolean isTest, boolean canDoze, int userId) {
mToken = token;
mName = name;
mIsTest = isTest;
+ mCanDoze = canDoze;
mUserId = userId;
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index ffb113c..fd2f8a1 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -30,16 +30,20 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.service.dreams.DreamService;
+import android.service.dreams.IDozeHardware;
import android.service.dreams.IDreamManager;
+import android.text.TextUtils;
import android.util.Slog;
import java.io.FileDescriptor;
@@ -64,11 +68,16 @@
private final DreamHandler mHandler;
private final DreamController mController;
private final PowerManager mPowerManager;
+ private final PowerManager.WakeLock mDozeWakeLock;
+ private final McuHal mMcuHal; // synchronized on self
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
private int mCurrentDreamUserId;
private boolean mCurrentDreamIsTest;
+ private boolean mCurrentDreamCanDoze;
+ private boolean mCurrentDreamIsDozing;
+ private DozeHardwareWrapper mCurrentDreamDozeHardware;
public DreamManagerService(Context context) {
super(context);
@@ -77,6 +86,12 @@
mController = new DreamController(context, mHandler, mControllerListener);
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
+
+ mMcuHal = McuHal.open();
+ if (mMcuHal != null) {
+ mMcuHal.reset();
+ }
}
@Override
@@ -103,10 +118,15 @@
pw.println("DREAM MANAGER (dumpsys dreams)");
pw.println();
+ pw.println("mMcuHal=" + mMcuHal);
+ pw.println();
pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
pw.println("mCurrentDreamName=" + mCurrentDreamName);
pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+ pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
+ pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
+ pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware);
pw.println();
DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
@@ -163,16 +183,16 @@
private void testDreamInternal(ComponentName dream, int userId) {
synchronized (mLock) {
- startDreamLocked(dream, true /*isTest*/, userId);
+ startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
}
}
- private void startDreamInternal() {
- int userId = ActivityManager.getCurrentUser();
- ComponentName dream = chooseDreamForUser(userId);
+ private void startDreamInternal(boolean doze) {
+ final int userId = ActivityManager.getCurrentUser();
+ final ComponentName dream = doze ? getDozeComponent() : chooseDreamForUser(userId);
if (dream != null) {
synchronized (mLock) {
- startDreamLocked(dream, false /*isTest*/, userId);
+ startDreamLocked(dream, false /*isTest*/, doze, userId);
}
}
}
@@ -183,6 +203,44 @@
}
}
+ private void startDozingInternal(IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream requested to start dozing: " + token);
+ }
+
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+ && !mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = true;
+ mDozeWakeLock.acquire();
+ }
+ }
+ }
+
+ private void stopDozingInternal(IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream requested to stop dozing: " + token);
+ }
+
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = false;
+ mDozeWakeLock.release();
+ }
+ }
+ }
+
+ private IDozeHardware getDozeHardwareInternal(IBinder token) {
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+ && mCurrentDreamDozeHardware == null && mMcuHal != null) {
+ mCurrentDreamDozeHardware = new DozeHardwareWrapper();
+ return mCurrentDreamDozeHardware;
+ }
+ return null;
+ }
+ }
+
private ComponentName chooseDreamForUser(int userId) {
ComponentName[] dreams = getDreamComponentsForUser(userId);
return dreams != null && dreams.length != 0 ? dreams[0] : null;
@@ -231,6 +289,20 @@
return name == null ? null : ComponentName.unflattenFromString(name);
}
+ private ComponentName getDozeComponent() {
+ // Read the component from a system property to facilitate debugging.
+ // Note that for production devices, the dream should actually be declared in
+ // a config.xml resource.
+ String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
+ if (TextUtils.isEmpty(name)) {
+ // Read the component from a config.xml resource.
+ // The value should be specified in a resource overlay for the product.
+ name = mContext.getResources().getString(
+ com.android.internal.R.string.config_dozeComponent);
+ }
+ return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name);
+ }
+
private boolean serviceExists(ComponentName name) {
try {
return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
@@ -240,9 +312,10 @@
}
private void startDreamLocked(final ComponentName name,
- final boolean isTest, final int userId) {
+ final boolean isTest, final boolean canDoze, final int userId) {
if (Objects.equal(mCurrentDreamName, name)
&& mCurrentDreamIsTest == isTest
+ && mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
return;
}
@@ -255,12 +328,13 @@
mCurrentDreamToken = newToken;
mCurrentDreamName = name;
mCurrentDreamIsTest = isTest;
+ mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
mHandler.post(new Runnable() {
@Override
public void run() {
- mController.startDream(newToken, name, isTest, userId);
+ mController.startDream(newToken, name, isTest, canDoze, userId);
}
});
}
@@ -284,7 +358,16 @@
mCurrentDreamToken = null;
mCurrentDreamName = null;
mCurrentDreamIsTest = false;
+ mCurrentDreamCanDoze = false;
mCurrentDreamUserId = 0;
+ if (mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = false;
+ mDozeWakeLock.release();
+ }
+ if (mCurrentDreamDozeHardware != null) {
+ mCurrentDreamDozeHardware.release();
+ mCurrentDreamDozeHardware = null;
+ }
}
private void checkPermission(String permission) {
@@ -473,12 +556,57 @@
Binder.restoreCallingIdentity(ident);
}
}
+
+ @Override // Binder call
+ public void startDozing(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ startDozingInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void stopDozing(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ stopDozingInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public IDozeHardware getDozeHardware(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDozeHardwareInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
private final class LocalService extends DreamManagerInternal {
@Override
- public void startDream() {
- startDreamInternal();
+ public void startDream(boolean doze) {
+ startDreamInternal(doze);
}
@Override
@@ -491,4 +619,37 @@
return isDreamingInternal();
}
}
+
+ private final class DozeHardwareWrapper extends IDozeHardware.Stub {
+ private boolean mReleased;
+
+ public void release() {
+ synchronized (mMcuHal) {
+ if (!mReleased) {
+ mReleased = true;
+ mMcuHal.reset();
+ }
+ }
+ }
+
+ @Override // Binder call
+ public byte[] sendMessage(String msg, byte[] arg) {
+ if (msg == null) {
+ throw new IllegalArgumentException("msg must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMcuHal) {
+ if (mReleased) {
+ throw new IllegalStateException("This operation cannot be performed "
+ + "because the dream has ended.");
+ }
+ return mMcuHal.sendMessage(msg, arg);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java
new file mode 100644
index 0000000..1dc79c7
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/McuHal.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.android.server.dreams;
+
+import android.service.dreams.DozeHardware;
+
+/**
+ * Provides access to the low-level microcontroller hardware abstraction layer.
+ */
+final class McuHal {
+ private final long mPtr;
+
+ private static native long nativeOpen();
+ private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg);
+
+ private McuHal(long ptr) {
+ mPtr = ptr;
+ }
+
+ public static McuHal open() {
+ long ptr = nativeOpen();
+ return ptr != 0 ? new McuHal(ptr) : null;
+ }
+
+ public void reset() {
+ sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF);
+ }
+
+ public byte[] sendMessage(String msg, byte[] arg) {
+ return nativeSendMessage(mPtr, msg, arg);
+ }
+}
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index eb7a383..62114cd 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -95,6 +95,7 @@
CategoryFilter.FACTORY,
SenderFilter.FACTORY,
+ SenderPackageFilter.FACTORY,
SenderPermissionFilter.FACTORY,
PortFilter.FACTORY
};
diff --git a/services/core/java/com/android/server/firewall/SenderPackageFilter.java b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
new file mode 100644
index 0000000..ec9b5de
--- /dev/null
+++ b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
@@ -0,0 +1,73 @@
+/*
+ * 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 com.android.server.firewall;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class SenderPackageFilter implements Filter {
+ private static final String ATTR_NAME = "name";
+
+ public final String mPackageName;
+
+ public SenderPackageFilter(String packageName) {
+ mPackageName = packageName;
+ }
+
+ @Override
+ public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+ int callerUid, int callerPid, String resolvedType, int receivingUid) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+
+ int packageUid = -1;
+ try {
+ packageUid = pm.getPackageUid(mPackageName, UserHandle.USER_OWNER);
+ } catch (RemoteException ex) {
+ // handled below
+ }
+
+ if (packageUid == -1) {
+ return false;
+ }
+
+ return UserHandle.isSameApp(packageUid, callerUid);
+ }
+
+ public static final FilterFactory FACTORY = new FilterFactory("sender-package") {
+ @Override
+ public Filter newFilter(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String packageName = parser.getAttributeValue(null, ATTR_NAME);
+
+ if (packageName == null) {
+ throw new XmlPullParserException(
+ "A package name must be specified.", parser, null);
+ }
+
+ return new SenderPackageFilter(packageName);
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3aa3851..e49382e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1366,8 +1366,9 @@
}
// Native callback.
- private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+ private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+ return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+ whenNanos, policyFlags);
}
// Native callback.
@@ -1527,7 +1528,7 @@
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 92ffdcc..b695b68 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -1,3 +1,19 @@
+/*
+ * 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 com.android.server.notification;
import android.app.Notification;
diff --git a/services/core/java/com/android/server/power/AutomaticBrightnessController.java b/services/core/java/com/android/server/power/AutomaticBrightnessController.java
index b24c572..3ca628a 100644
--- a/services/core/java/com/android/server/power/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/power/AutomaticBrightnessController.java
@@ -201,7 +201,7 @@
public void updatePowerState(DisplayPowerRequest request) {
if (setScreenAutoBrightnessAdjustment(request.screenAutoBrightnessAdjustment)
|| setLightSensorEnabled(request.useAutoBrightness
- && DisplayPowerRequest.wantScreenOn(request.screenState))) {
+ && request.wantScreenOnNormal())) {
updateAutoBrightness(false /*sendUpdate*/);
}
}
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index 291bb64..12d51aa 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -147,6 +147,9 @@
// The proximity sensor, or null if not available or needed.
private Sensor mProximitySensor;
+ // The doze screen brightness.
+ private final int mScreenBrightnessDozeConfig;
+
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
@@ -259,6 +262,9 @@
final Resources resources = context.getResources();
+ mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDoze));
+
mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim));
@@ -432,7 +438,7 @@
// Update the power state request.
final boolean mustNotify;
boolean mustInitialize = false;
- boolean wasDim = false;
+ boolean wasDimOrDoze = false;
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
@@ -447,7 +453,8 @@
mPendingRequestChangedLocked = false;
mustInitialize = true;
} else if (mPendingRequestChangedLocked) {
- wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
+ wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
+ || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
mPowerRequest.copyFrom(mPendingRequestLocked);
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
@@ -498,12 +505,12 @@
}
// Set the screen brightness.
- if (DisplayPowerRequest.wantScreenOn(mPowerRequest.screenState)) {
+ if (mPowerRequest.wantScreenOnAny()) {
int target;
boolean slow;
int screenAutoBrightness = mAutomaticBrightnessController != null ?
mAutomaticBrightnessController.getAutomaticScreenBrightness() : -1;
- if (screenAutoBrightness >= 0) {
+ if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) {
// Use current auto-brightness value.
target = screenAutoBrightness;
slow = mUsingScreenAutoBrightness;
@@ -517,12 +524,16 @@
slow = false;
mUsingScreenAutoBrightness = false;
}
- if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+ if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
+ // Dim quickly to the doze state.
+ target = mScreenBrightnessDozeConfig;
+ slow = false;
+ } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
// Dim quickly by at least some minimum amount.
target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig);
slow = false;
- } else if (wasDim) {
+ } else if (wasDimOrDoze) {
// Brighten quickly.
slow = false;
}
@@ -535,7 +546,7 @@
// Animate the screen on or off.
if (!mScreenOffBecauseOfProximity) {
- if (DisplayPowerRequest.wantScreenOn(mPowerRequest.screenState)) {
+ if (mPowerRequest.wantScreenOnAny()) {
// Want screen on.
// Wait for previous off animation to complete beforehand.
// It is relatively short but if we cancel it and switch to the
@@ -804,6 +815,7 @@
pw.println();
pw.println("Display Controller Configuration:");
+ pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
diff --git a/services/core/java/com/android/server/power/DisplayPowerRequest.java b/services/core/java/com/android/server/power/DisplayPowerRequest.java
index 7626f76..c5e46cb 100644
--- a/services/core/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/core/java/com/android/server/power/DisplayPowerRequest.java
@@ -30,10 +30,11 @@
*/
final class DisplayPowerRequest {
public static final int SCREEN_STATE_OFF = 0;
- public static final int SCREEN_STATE_DIM = 1;
- public static final int SCREEN_STATE_BRIGHT = 2;
+ public static final int SCREEN_STATE_DOZE = 1;
+ public static final int SCREEN_STATE_DIM = 2;
+ public static final int SCREEN_STATE_BRIGHT = 3;
- // The requested minimum screen power state: off, dim or bright.
+ // The requested minimum screen power state: off, doze, dim or bright.
public int screenState;
// If true, the proximity sensor overrides the screen state when an object is
@@ -75,6 +76,23 @@
copyFrom(other);
}
+ // Returns true if we want the screen on in any mode, including doze.
+ public boolean wantScreenOnAny() {
+ return screenState != SCREEN_STATE_OFF;
+ }
+
+ // Returns true if we want the screen on in a normal mode, excluding doze.
+ // This is usually what we want to tell the rest of the system. For compatibility
+ // reasons, we pretend the screen is off when dozing.
+ public boolean wantScreenOnNormal() {
+ return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT;
+ }
+
+ public boolean wantLightSensorEnabled() {
+ // Specifically, we don't want the light sensor while dozing.
+ return useAutoBrightness && wantScreenOnNormal();
+ }
+
public void copyFrom(DisplayPowerRequest other) {
screenState = other.screenState;
useProximitySensor = other.useProximitySensor;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ecde184..0ba55b6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -83,7 +83,7 @@
// Message: Sent when a user activity timeout occurs to update the power state.
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
- // Message: Sent when the device enters or exits a napping or dreaming state.
+ // Message: Sent when the device enters or exits a dreaming or dozing state.
private static final int MSG_SANDMAN = 2;
// Message: Sent when the screen on blocker is released.
private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
@@ -117,19 +117,21 @@
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
+ // The device typically passes through the dozing state first.
private static final int WAKEFULNESS_ASLEEP = 0;
// Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep().
- // When the user activity timeout expires, the device may start napping or go to sleep.
+ // When the user activity timeout expires, the device may start dreaming or go to sleep.
private static final int WAKEFULNESS_AWAKE = 1;
- // Wakefulness: The device is napping. It is deciding whether to dream or go to sleep
- // but hasn't gotten around to it yet. It can be awoken by a call to wakeUp(), which
- // ends the nap. User activity may brighten the screen but does not end the nap.
- private static final int WAKEFULNESS_NAPPING = 2;
// Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(),
// which ends the dream. The device goes to sleep when goToSleep() is called, when
// the dream ends or when unplugged.
// User activity may brighten the screen but does not end the dream.
- private static final int WAKEFULNESS_DREAMING = 3;
+ private static final int WAKEFULNESS_DREAMING = 2;
+ // Wakefulness: The device is dozing. It is almost asleep but is allowing a special
+ // low-power "doze" dream to run which keeps the display on but lets the application
+ // processor be suspended. It can be awoken by a call to wakeUp() which ends the dream.
+ // The device fully goes to sleep if the dream cannot be started or ends on its own.
+ private static final int WAKEFULNESS_DOZING = 3;
// Summarizes the state of all active wakelocks.
private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -138,6 +140,7 @@
private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
+ private static final int WAKE_LOCK_DOZE = 1 << 6;
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -164,11 +167,6 @@
// Poll interval in milliseconds for watching boot animation finished.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
- // If the battery level drops by this percentage and the user activity timeout
- // has expired, then assume the device is receiving insufficient current to charge
- // effectively and terminate the dream.
- private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
-
private final Context mContext;
private LightsManager mLightsManager;
private BatteryService mBatteryService;
@@ -195,6 +193,10 @@
// This is distinct from the screen power state, which is managed separately.
private int mWakefulness;
+ // True if the sandman has just been summoned for the first time since entering the
+ // dreaming or dozing state. Indicates whether a new dream should begin.
+ private boolean mSandmanSummoned;
+
// True if MSG_SANDMAN has been scheduled.
private boolean mSandmanScheduled;
@@ -265,6 +267,14 @@
// True if boot completed occurred. We keep the screen on until this happens.
private boolean mBootCompleted;
+ // True if auto-suspend mode is enabled.
+ // Refer to autosuspend.h.
+ private boolean mAutoSuspendModeEnabled;
+
+ // True if interactive mode is enabled.
+ // Refer to power.h.
+ private boolean mInteractiveModeEnabled;
+
// True if the device is plugged into a power source.
private boolean mIsPowered;
@@ -282,6 +292,12 @@
// The current dock state.
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ // True to decouple auto-suspend mode from the display state.
+ private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+
+ // True to decouple interactive mode from the display state.
+ private boolean mDecoupleInteractiveModeFromDisplayConfig;
+
// True if the device should wake up when plugged or unplugged.
private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
@@ -300,6 +316,22 @@
// Default value for dreams activate-on-dock
private boolean mDreamsActivatedOnDockByDefaultConfig;
+ // True if dreams can run while not plugged in.
+ private boolean mDreamsEnabledOnBatteryConfig;
+
+ // Minimum battery level to allow dreaming when powered.
+ // Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelMinimumWhenPoweredConfig;
+
+ // Minimum battery level to allow dreaming when not powered.
+ // Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig;
+
+ // If the battery level drops by this percentage and the user activity timeout
+ // has expired, then assume the device is receiving insufficient current to charge
+ // effectively and terminate the dream. Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelDrainCutoffConfig;
+
// True if dreams are enabled by the user.
private boolean mDreamsEnabledSetting;
@@ -523,6 +555,10 @@
private void readConfigurationLocked() {
final Resources resources = mContext.getResources();
+ mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
+ mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
@@ -535,6 +571,14 @@
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+ mDreamsEnabledOnBatteryConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsEnabledOnBattery);
+ mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered);
+ mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered);
+ mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
}
private void updateSettingsLocked() {
@@ -762,6 +806,7 @@
case PowerManager.SCREEN_DIM_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.DOZE_WAKE_LOCK:
return true;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
@@ -794,7 +839,8 @@
}
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
- || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) {
+ || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING
+ || !mBootCompleted || !mSystemReady) {
return false;
}
@@ -843,18 +889,21 @@
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep...");
- sendPendingNotificationsLocked();
- mNotifier.onWakeUpStarted();
- mSendWakeUpFinishedNotificationWhenReady = true;
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream...");
break;
- case WAKEFULNESS_NAPPING:
- Slog.i(TAG, "Waking up from nap...");
+ case WAKEFULNESS_DOZING:
+ Slog.i(TAG, "Waking up from dozing...");
break;
}
+ if (mWakefulness != WAKEFULNESS_DREAMING) {
+ sendPendingNotificationsLocked();
+ mNotifier.onWakeUpStarted();
+ mSendWakeUpFinishedNotificationWhenReady = true;
+ }
+
mLastWakeTime = eventTime;
mWakefulness = WAKEFULNESS_AWAKE;
mDirty |= DIRTY_WAKEFULNESS;
@@ -877,13 +926,17 @@
}
}
+ // This method is called goToSleep for historical reasons but we actually start
+ // dozing before really going to sleep.
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
}
- if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ if (eventTime < mLastWakeTime
+ || mWakefulness == WAKEFULNESS_ASLEEP
+ || mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
@@ -907,7 +960,8 @@
mLastSleepTime = eventTime;
mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_ASLEEP;
+ mWakefulness = WAKEFULNESS_DOZING;
+ mSandmanSummoned = true;
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
@@ -947,7 +1001,26 @@
Slog.i(TAG, "Nap time...");
mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_NAPPING;
+ mWakefulness = WAKEFULNESS_DREAMING;
+ mSandmanSummoned = true;
+ return true;
+ }
+
+ // Done dozing, drop everything and go to sleep.
+ private boolean reallyGoToSleepNoUpdateLocked(long eventTime) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime);
+ }
+
+ if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ || !mBootCompleted || !mSystemReady) {
+ return false;
+ }
+
+ Slog.i(TAG, "Sleeping...");
+
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_ASLEEP;
return true;
}
@@ -1023,7 +1096,7 @@
mPlugType = mBatteryService.getPlugType();
mBatteryLevel = mBatteryService.getBatteryLevel();
- if (DEBUG) {
+ if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
+ ", mIsPowered=" + mIsPowered
+ ", oldPlugType=" + oldPlugType
@@ -1083,8 +1156,7 @@
}
// If already dreaming and becoming powered, then don't wake.
- if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
- || mWakefulness == WAKEFULNESS_DREAMING)) {
+ if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
return false;
}
@@ -1131,35 +1203,45 @@
mWakeLockSummary |= WAKE_LOCK_CPU;
break;
case PowerManager.FULL_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ 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;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING
+ || mWakefulness == WAKEFULNESS_DOZING) {
mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
break;
+ case PowerManager.DOZE_WAKE_LOCK:
+ if (mWakefulness == WAKEFULNESS_DOZING) {
+ mWakeLockSummary |= WAKE_LOCK_DOZE;
+ }
+ break;
}
}
@@ -1184,7 +1266,8 @@
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
final int screenOffTimeout = getScreenOffTimeoutLocked();
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
@@ -1205,8 +1288,7 @@
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout
- && mDisplayPowerRequest.screenState
- != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ && mDisplayPowerRequest.wantScreenOnNormal()) {
mUserActivitySummary = mDisplayPowerRequest.screenState
== DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
@@ -1268,7 +1350,7 @@
/**
* Updates the wakefulness of the device.
*
- * This is the function that decides whether the device should start napping
+ * This is the function that decides whether the device should start dreaming
* based on the current wake locks and user activity state. It may modify mDirty
* if the wakefulness changes.
*
@@ -1357,7 +1439,7 @@
}
/**
- * Called when the device enters or exits a napping or dreaming state.
+ * Called when the device enters or exits a dreaming or dozing state.
*
* We do this asynchronously because we must call out of the power manager to start
* the dream and we don't want to hold our lock while doing so. There is a risk that
@@ -1365,46 +1447,60 @@
*/
private void handleSandman() { // runs on handler thread
// Handle preconditions.
- boolean startDreaming = false;
+ final boolean startDreaming;
+ final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
- boolean canDream = canDreamLocked();
- if (DEBUG_SPEW) {
- Slog.d(TAG, "handleSandman: canDream=" + canDream
- + ", mWakefulness=" + wakefulnessToString(mWakefulness));
- }
-
- if (canDream && mWakefulness == WAKEFULNESS_NAPPING) {
- startDreaming = true;
+ wakefulness = mWakefulness;
+ if (mSandmanSummoned) {
+ startDreaming = ((wakefulness == WAKEFULNESS_DREAMING && canDreamLocked())
+ || wakefulness == WAKEFULNESS_DOZING);
+ mSandmanSummoned = false;
+ } else {
+ startDreaming = false;
}
}
// Start dreaming if needed.
// We only control the dream on the handler thread, so we don't need to worry about
// concurrent attempts to start or stop the dream.
- boolean isDreaming = false;
+ final boolean isDreaming;
if (mDreamManager != null) {
+ // Restart the dream whenever the sandman is summoned.
if (startDreaming) {
- mDreamManager.startDream();
+ mDreamManager.stopDream();
+ mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
}
isDreaming = mDreamManager.isDreaming();
+ } else {
+ isDreaming = false;
}
// Update dream state.
- // We might need to stop the dream again if the preconditions changed.
- boolean continueDreaming = false;
synchronized (mLock) {
- if (isDreaming && canDreamLocked()) {
- if (mWakefulness == WAKEFULNESS_NAPPING) {
- mWakefulness = WAKEFULNESS_DREAMING;
- mDirty |= DIRTY_WAKEFULNESS;
- mBatteryLevelWhenDreamStarted = mBatteryLevel;
- updatePowerStateLocked();
- continueDreaming = true;
- } else if (mWakefulness == WAKEFULNESS_DREAMING) {
- if (!isBeingKeptAwakeLocked()
+ // Remember the initial battery level when the dream started.
+ if (startDreaming && isDreaming) {
+ mBatteryLevelWhenDreamStarted = mBatteryLevel;
+ if (wakefulness == WAKEFULNESS_DOZING) {
+ Slog.i(TAG, "Dozing...");
+ } else {
+ Slog.i(TAG, "Dreaming...");
+ }
+ }
+
+ // If preconditions changed, wait for the next iteration to determine
+ // whether the dream should continue (or be restarted).
+ if (mSandmanSummoned || mWakefulness != wakefulness) {
+ return; // wait for next cycle
+ }
+
+ // Determine whether the dream should continue.
+ if (wakefulness == WAKEFULNESS_DREAMING) {
+ if (isDreaming && canDreamLocked()) {
+ if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) {
+ - mDreamsBatteryLevelDrainCutoffConfig
+ && !isBeingKeptAwakeLocked()) {
// If the user activity timeout expired and the battery appears
// to be draining faster than it is charging then stop dreaming
// and go to sleep.
@@ -1414,53 +1510,64 @@
+ mBatteryLevelWhenDreamStarted + "%. "
+ "Battery level now: " + mBatteryLevel + "%.");
} else {
- continueDreaming = true;
+ return; // continue dreaming
}
}
- }
- if (!continueDreaming) {
- handleDreamFinishedLocked();
+
+ // Dream has ended or will be stopped. Update the power state.
+ if (isItBedTimeYetLocked()) {
+ goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ updatePowerStateLocked();
+ } else {
+ wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
+ updatePowerStateLocked();
+ }
+ } else if (wakefulness == WAKEFULNESS_DOZING) {
+ if (isDreaming) {
+ return; // continue dozing
+ }
+
+ // Doze has ended or will be stopped. Update the power state.
+ reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis());
+ updatePowerStateLocked();
}
}
- // Stop dreaming if needed.
- // It's possible that something else changed to make us need to start the dream again.
- // If so, then the power manager will have posted another message to the handler
- // to take care of it later.
- if (mDreamManager != null) {
- if (!continueDreaming) {
- mDreamManager.stopDream();
- }
+ // Stop dream.
+ if (isDreaming) {
+ mDreamManager.stopDream();
}
}
/**
- * Returns true if the device is allowed to dream in its current state
- * assuming that it is currently napping or dreaming.
+ * Returns true if the device is allowed to dream in its current state.
+ * This function is not called when dozing.
*/
private boolean canDreamLocked() {
- return mDreamsSupportedConfig
- && mDreamsEnabledSetting
- && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
- && mBootCompleted
- && (mIsPowered || isBeingKeptAwakeLocked());
- }
-
- /**
- * Called when a dream is ending to figure out what to do next.
- */
- private void handleDreamFinishedLocked() {
- if (mWakefulness == WAKEFULNESS_NAPPING
- || mWakefulness == WAKEFULNESS_DREAMING) {
- if (isItBedTimeYetLocked()) {
- goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- updatePowerStateLocked();
- } else {
- wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
- updatePowerStateLocked();
+ if (mWakefulness != WAKEFULNESS_DREAMING
+ || !mDreamsSupportedConfig
+ || !mDreamsEnabledSetting
+ || !mDisplayPowerRequest.wantScreenOnNormal()
+ || !mBootCompleted) {
+ return false;
+ }
+ if (!isBeingKeptAwakeLocked()) {
+ if (!mIsPowered && !mDreamsEnabledByDefaultConfig) {
+ return false;
+ }
+ if (!mIsPowered
+ && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
+ && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {
+ return false;
+ }
+ if (mIsPowered
+ && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0
+ && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {
+ return false;
}
}
+ return true;
}
private void handleScreenOnBlockerReleased() {
@@ -1482,11 +1589,11 @@
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
- int newScreenState = getDesiredScreenPowerStateLocked();
+ final int newScreenState = getDesiredScreenPowerStateLocked();
if (newScreenState != mDisplayPowerRequest.screenState) {
mDisplayPowerRequest.screenState = newScreenState;
nativeSetPowerState(
- newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF,
+ mDisplayPowerRequest.wantScreenOnNormal(),
newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
}
@@ -1555,6 +1662,10 @@
return DisplayPowerRequest.SCREEN_STATE_OFF;
}
+ if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+ return DisplayPowerRequest.SCREEN_STATE_DOZE;
+ }
+
if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
|| (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
|| !mBootCompleted) {
@@ -1606,7 +1717,18 @@
*/
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
- final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
+ final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
+ final boolean autoSuspend = !needDisplaySuspendBlocker;
+
+ // Disable auto-suspend if needed.
+ if (!autoSuspend) {
+ if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(false);
+ }
+ if (mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(true);
+ }
+ }
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1627,17 +1749,27 @@
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
+
+ // Enable auto-suspend if needed.
+ if (autoSuspend) {
+ if (mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(false);
+ }
+ if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(true);
+ }
+ }
}
/**
* Return true if we must keep a suspend blocker active on behalf of the display.
* We do so if the screen is on or is in transition between states.
*/
- private boolean needDisplaySuspendBlocker() {
+ private boolean needDisplaySuspendBlockerLocked() {
if (!mDisplayReady) {
return true;
}
- if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ if (mDisplayPowerRequest.wantScreenOnNormal()) {
// If we asked for the screen to be on but it is off due to the proximity
// sensor then we may suspend but only if the configuration allows it.
// On some hardware it may not be safe to suspend because the proximity
@@ -1647,13 +1779,34 @@
return true;
}
}
+ // Let the system suspend if the screen is off or dozing.
return false;
}
+ private void setAutoSuspendModeLocked(boolean enable) {
+ if (enable != mAutoSuspendModeEnabled) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+ }
+ mAutoSuspendModeEnabled = enable;
+ nativeSetAutoSuspend(enable);
+ }
+ }
+
+ private void setInteractiveModeLocked(boolean enable) {
+ if (enable != mInteractiveModeEnabled) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting interactive mode to " + enable);
+ }
+ mInteractiveModeEnabled = enable;
+ nativeSetInteractive(enable);
+ }
+ }
+
private boolean isScreenOnInternal() {
synchronized (mLock) {
return !mSystemReady
- || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
+ || mDisplayPowerRequest.wantScreenOnNormal();
}
}
@@ -1887,10 +2040,13 @@
pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
+ pw.println(" mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
+ pw.println(" mInteactiveModeEnabled=" + mInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
+ pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
pw.println(" mSendWakeUpFinishedNotificationWhenReady="
@@ -1906,6 +2062,10 @@
pw.println();
pw.println("Settings and Configuration:");
+ pw.println(" mDecoupleAutoSuspendModeFromDisplayConfig="
+ + mDecoupleAutoSuspendModeFromDisplayConfig);
+ pw.println(" mDecoupleInteractiveModeFromDisplayConfig="
+ + mDecoupleInteractiveModeFromDisplayConfig);
pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig="
+ mWakeUpWhenPluggedOrUnpluggedConfig);
pw.println(" mSuspendWhenScreenOffDueToProximityConfig="
@@ -1916,6 +2076,14 @@
+ mDreamsActivatedOnSleepByDefaultConfig);
pw.println(" mDreamsActivatedOnDockByDefaultConfig="
+ mDreamsActivatedOnDockByDefaultConfig);
+ pw.println(" mDreamsEnabledOnBatteryConfig="
+ + mDreamsEnabledOnBatteryConfig);
+ pw.println(" mDreamsBatteryLevelMinimumWhenPoweredConfig="
+ + mDreamsBatteryLevelMinimumWhenPoweredConfig);
+ pw.println(" mDreamsBatteryLevelMinimumWhenNotPoweredConfig="
+ + mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+ pw.println(" mDreamsBatteryLevelDrainCutoffConfig="
+ + mDreamsBatteryLevelDrainCutoffConfig);
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
@@ -1991,8 +2159,8 @@
return "Awake";
case WAKEFULNESS_DREAMING:
return "Dreaming";
- case WAKEFULNESS_NAPPING:
- return "Napping";
+ case WAKEFULNESS_DOZING:
+ return "Dozing";
default:
return Integer.toString(wakefulness);
}
@@ -2169,6 +2337,7 @@
+ " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")";
}
+ @SuppressWarnings("deprecation")
private String getLockLevelString() {
switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
@@ -2181,6 +2350,8 @@
return "PARTIAL_WAKE_LOCK ";
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
+ case PowerManager.DOZE_WAKE_LOCK:
+ return "DOZE_WAKE_LOCK ";
default:
return "??? ";
}
@@ -2311,16 +2482,24 @@
synchronized (this) {
mBlanked = true;
mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
- nativeSetInteractive(false);
- nativeSetAutoSuspend(true);
+ if (!mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(false);
+ }
+ if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(true);
+ }
}
}
@Override
public void unblankAllDisplays() {
synchronized (this) {
- nativeSetAutoSuspend(false);
- nativeSetInteractive(true);
+ if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(true);
+ }
mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
mBlanked = false;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 3cccf1d..7fe895b 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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 com.android.server.wm;
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index aa7d485..c09ea5c 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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 com.android.server.wm;
@@ -125,12 +139,53 @@
}
}
+ /**
+ * @param layer The new layer value.
+ * @param inTransaction Whether the call is made within a surface transaction.
+ */
+ void adjustSurface(int layer, boolean inTransaction) {
+ final int dw, dh;
+ final float xPos, yPos;
+ if (!mStack.isFullscreen()) {
+ dw = mBounds.width();
+ dh = mBounds.height();
+ xPos = mBounds.left;
+ yPos = mBounds.top;
+ } else {
+ // Set surface size to screen size.
+ final DisplayInfo info = mDisplayContent.getDisplayInfo();
+ // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose
+ // a corner.
+ dw = (int) (info.logicalWidth * 1.5);
+ dh = (int) (info.logicalHeight * 1.5);
+ // back off position so 1/4 of Surface is before and 1/4 is after.
+ xPos = -1 * dw / 6;
+ yPos = -1 * dh / 6;
+ }
+
+ try {
+ if (!inTransaction) {
+ SurfaceControl.openTransaction();
+ }
+ mDimSurface.setPosition(xPos, yPos);
+ mDimSurface.setSize(dw, dh);
+ mDimSurface.setLayer(layer);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting size or layer", e);
+ } finally {
+ if (!inTransaction) {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ mLastBounds.set(mBounds);
+ mLayer = layer;
+ }
+
+ // Assumes that surface transactions are currently closed.
void setBounds(Rect bounds) {
mBounds.set(bounds);
if (isDimming() && !mLastBounds.equals(bounds)) {
- // Clearing mAlpha forces show to redisplay with new size.
- mAlpha = 0;
- show();
+ adjustSurface(mLayer, false);
}
}
@@ -169,35 +224,8 @@
return;
}
- final int dw, dh;
- final float xPos, yPos;
- if (!mStack.isFullscreen()) {
- dw = mBounds.width();
- dh = mBounds.height();
- xPos = mBounds.left;
- yPos = mBounds.top;
- } else {
- // Set surface size to screen size.
- final DisplayInfo info = mDisplayContent.getDisplayInfo();
- // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
- // corner.
- dw = (int) (info.logicalWidth * 1.5);
- dh = (int) (info.logicalHeight * 1.5);
- // back off position so 1/4 of Surface is before and 1/4 is after.
- xPos = -1 * dw / 6;
- yPos = -1 * dh / 6;
- }
-
if (!mLastBounds.equals(mBounds) || mLayer != layer) {
- try {
- mDimSurface.setPosition(xPos, yPos);
- mDimSurface.setSize(dw, dh);
- mDimSurface.setLayer(layer);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Failure setting size or layer", e);
- }
- mLastBounds.set(mBounds);
- mLayer = layer;
+ adjustSurface(layer, true);
}
long curTime = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 803b9ac..4aae5c1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -364,8 +364,8 @@
* motion event processing when the screen is off since these events are normally
* dropped. */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+ return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(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/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index a9947c0..0c68258 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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 com.android.server.wm;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f46056b..1747d01 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4208,10 +4208,25 @@
AppWindowToken atoken = findAppWindowToken(token);
if (atoken != null) {
atoken.appFullscreen = toOpaque;
+ // When making translucent, wait until windows below have been drawn.
+ if (toOpaque) {
+ // Making opaque so do it now.
+ setWindowOpaque(token, true);
+ }
requestTraversal();
}
}
+ public void setWindowOpaque(IBinder token, boolean isOpaque) {
+ AppWindowToken wtoken = findAppWindowToken(token);
+ if (wtoken != null) {
+ WindowState win = wtoken.findMainWindow();
+ if (win != null) {
+ win.mWinAnimator.setOpaque(isOpaque);
+ }
+ }
+ }
+
boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
boolean visible, int transit, boolean performLayout) {
boolean delayed = false;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ffb17f1..f98b724 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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 com.android.server.wm;
@@ -490,6 +504,7 @@
private final Rect mWindowCrop = new Rect();
private boolean mShown = false;
private int mLayerStack;
+ private boolean mIsOpaque;
private final String mName;
public SurfaceTrace(SurfaceSession s,
@@ -575,6 +590,16 @@
}
@Override
+ public void setOpaque(boolean isOpaque) {
+ if (isOpaque != mIsOpaque) {
+ Slog.v(SURFACE_TAG, "setOpaque(" + isOpaque + "): OLD:" + this
+ + ". Called by " + Debug.getCallers(3));
+ mIsOpaque = isOpaque;
+ }
+ super.setOpaque(isOpaque);
+ }
+
+ @Override
public void hide() {
if (mShown) {
Slog.v(SURFACE_TAG, "hide: OLD:" + this + ". Called by " + Debug.getCallers(3));
@@ -620,7 +645,8 @@
+ mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer
+ " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
+ " " + mSize.x + "x" + mSize.y
- + " crop=" + mWindowCrop.toShortString();
+ + " crop=" + mWindowCrop.toShortString()
+ + " opaque=" + mIsOpaque;
}
}
@@ -1337,8 +1363,7 @@
Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true");
return;
}
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- ">>> OPEN TRANSACTION setTransparentRegion");
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setTransparentRegion");
SurfaceControl.openTransaction();
try {
if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
@@ -1364,8 +1389,7 @@
// transformation is being applied by the animation.
return;
}
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- ">>> OPEN TRANSACTION setWallpaperOffset");
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
SurfaceControl.openTransaction();
try {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
@@ -1383,6 +1407,22 @@
}
}
+ void setOpaque(boolean isOpaque) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setOpaque");
+ SurfaceControl.openTransaction();
+ try {
+ if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "isOpaque=" + isOpaque,
+ null);
+ mSurfaceControl.setOpaque(isOpaque);
+ } finally {
+ SurfaceControl.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setOpaque");
+ }
+ }
+
// This must be called while inside a transaction.
boolean performShowLocked() {
if (mWin.isHiddenFromUserLocked()) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 85f69a4..7675ba6 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -8,6 +8,7 @@
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 4a1b55d..163692b 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -73,7 +73,7 @@
SkSafeUnref(previousCanvas);
}
-static SkBitmap* com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
+static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
jobject canvas, jint width, jint height) {
SkBitmap* bitmap = new SkBitmap;
@@ -84,12 +84,13 @@
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
swapCanvasPtr(env, canvas, nativeCanvas);
- return bitmap;
+ return reinterpret_cast<jlong>(bitmap);
}
static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject,
- jobject canvas, SkBitmap* bitmap) {
+ jobject canvas, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
swapCanvasPtr(env, canvas, nativeCanvas);
@@ -108,21 +109,22 @@
return result;
static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
- jobject graphicBuffer, SkBitmap* bitmap) {
+ jobject graphicBuffer, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
// The goal of this method is to copy the bitmap into the GraphicBuffer
// using the GPU to swizzle the texture content
sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
if (buffer != NULL) {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (display == EGL_NO_DISPLAY) return false;
+ if (display == EGL_NO_DISPLAY) return JNI_FALSE;
EGLint major;
EGLint minor;
if (!eglInitialize(display, &major, &minor)) {
ALOGW("Could not initialize EGL");
- return false;
+ return JNI_FALSE;
}
// We're going to use a 1x1 pbuffer surface later on
@@ -143,13 +145,13 @@
ALOGW("Could not select EGL configuration");
eglReleaseThread();
eglTerminate(display);
- return false;
+ return JNI_FALSE;
}
if (configCount <= 0) {
ALOGW("Could not find EGL configuration");
eglReleaseThread();
eglTerminate(display);
- return false;
+ return JNI_FALSE;
}
// These objects are initialized below but the default "null"
@@ -164,7 +166,7 @@
EGLContext context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, attrs);
if (context == EGL_NO_CONTEXT) {
ALOGW("Could not create EGL context");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// Create the 1x1 pbuffer
@@ -172,12 +174,12 @@
surface = eglCreatePbufferSurface(display, configs[0], surfaceAttrs);
if (surface == EGL_NO_SURFACE) {
ALOGW("Could not create EGL surface");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
if (!eglMakeCurrent(display, surface, surface, context)) {
ALOGW("Could not change current EGL context");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// We use an EGLImage to access the content of the GraphicBuffer
@@ -188,7 +190,7 @@
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
if (image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
glGenTextures(1, &texture);
@@ -196,7 +198,7 @@
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
if (glGetError() != GL_NO_ERROR) {
ALOGW("Could not create/bind texture");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// Upload the content of the bitmap in the GraphicBuffer
@@ -205,7 +207,7 @@
GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
if (glGetError() != GL_NO_ERROR) {
ALOGW("Could not upload to texture");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// The fence is used to wait for the texture upload to finish
@@ -214,7 +216,7 @@
fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
if (fence == EGL_NO_SYNC_KHR) {
ALOGW("Could not create sync fence %#x", eglGetError());
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
@@ -223,13 +225,13 @@
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
ALOGW("Failed to wait for the fence %#x", eglGetError());
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
- CLEANUP_GL_AND_RETURN(true);
+ CLEANUP_GL_AND_RETURN(JNI_TRUE);
}
- return false;
+ return JNI_FALSE;
}
// ----------------------------------------------------------------------------
@@ -247,11 +249,11 @@
const char* const kClassPathName = "com/android/server/AssetAtlasService";
static JNINativeMethod gMethods[] = {
- { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)I",
+ { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)J",
(void*) com_android_server_AssetAtlasService_acquireCanvas },
- { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;I)V",
+ { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;J)V",
(void*) com_android_server_AssetAtlasService_releaseCanvas },
- { "nUploadAtlas", "(Landroid/view/GraphicBuffer;I)Z",
+ { "nUploadAtlas", "(Landroid/view/GraphicBuffer;J)Z",
(void*) com_android_server_AssetAtlasService_upload },
};
diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp
new file mode 100644
index 0000000..a6d9297
--- /dev/null
+++ b/services/core/jni/com_android_server_dreams_McuHal.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "McuHal"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <ScopedUtfChars.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <hardware/mcu.h>
+
+namespace android {
+
+static jlong nativeOpen(JNIEnv* env, jclass clazz) {
+ mcu_module_t* module = NULL;
+ status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&module);
+ if (err) {
+ ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+ return 0;
+ }
+
+ err = module->init(module);
+ if (err) {
+ ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+ return 0;
+ }
+
+ return reinterpret_cast<jlong>(module);
+}
+
+static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz,
+ jlong ptr, jstring msgStr, jbyteArray argArray) {
+ mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr);
+
+ ScopedUtfChars msg(env, msgStr);
+ ALOGV("Sending message %s to MCU", msg.c_str());
+
+ void* result = NULL;
+ size_t resultSize = 0;
+ status_t err;
+ if (argArray) {
+ ScopedByteArrayRO arg(env, argArray);
+ err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(),
+ &result, &resultSize);
+ } else {
+ err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize);
+ }
+ if (err) {
+ ALOGE("Couldn't send message to MCU (%s)", strerror(-err));
+ return NULL;
+ }
+
+ if (!result) {
+ return NULL;
+ }
+
+ jbyteArray resultArray = env->NewByteArray(resultSize);
+ if (resultArray) {
+ env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result));
+ }
+ free(result);
+ return resultArray;
+}
+
+static JNINativeMethod gMcuHalMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeOpen", "()J",
+ (void*) nativeOpen },
+ { "nativeSendMessage", "(JLjava/lang/String;[B)[B",
+ (void*) nativeSendMessage },
+};
+
+int register_android_server_dreams_McuHal(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal",
+ gMcuHalMethods, NELEM(gMcuHalMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9fe0082..0207c55 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -151,8 +151,6 @@
enum {
WM_ACTION_PASS_TO_USER = 1,
- WM_ACTION_WAKE_UP = 2,
- WM_ACTION_GO_TO_SLEEP = 4,
};
@@ -844,7 +842,7 @@
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
- policyFlags);
+ when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingWhenScreenOff")) {
wmActions = 0;
@@ -860,20 +858,6 @@
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
- if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("handleInterceptActions: Going to sleep.");
-#endif
- android_server_PowerManagerService_goToSleep(when);
- }
-
- if (wmActions & WM_ACTION_WAKE_UP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("handleInterceptActions: Waking up.");
-#endif
- android_server_PowerManagerService_wakeUp(when);
- }
-
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
@@ -1412,7 +1396,7 @@
GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
clazz,
- "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
+ "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
"interceptKeyBeforeDispatching",
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index efc34a2..00986d5 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -36,6 +36,7 @@
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
+int register_android_server_dreams_McuHal(JNIEnv* env);
};
using namespace android;
@@ -67,7 +68,7 @@
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
-
+ register_android_server_dreams_McuHal(env);
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 12f0114..f9a5e5d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1315,9 +1315,7 @@
}
if (admin.getUid() != Binder.getCallingUid()) {
// If trying to remove device owner, refuse when the caller is not the owner.
- if (mDeviceOwner != null
- && adminReceiver.getPackageName().equals(
- mDeviceOwner.getDeviceOwnerPackageName())) {
+ if (isDeviceOwner(adminReceiver.getPackageName())) {
return;
}
mContext.enforceCallingOrSelfPermission(
@@ -2793,6 +2791,7 @@
}
synchronized (this) {
return mDeviceOwner != null
+ && mDeviceOwner.hasDeviceOwner()
&& mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
}
}
diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk
new file mode 100644
index 0000000..01f10e5
--- /dev/null
+++ b/tests/DozeTest/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := DozeTest
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/DozeTest/AndroidManifest.xml b/tests/DozeTest/AndroidManifest.xml
new file mode 100644
index 0000000..c199f69
--- /dev/null
+++ b/tests/DozeTest/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.dreams.dozetest">
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <application android:label="@string/app_name">
+ <service
+ android:name="DozeTestDream"
+ android:exported="true"
+ android:icon="@drawable/ic_app"
+ android:label="@string/doze_dream_name">
+ <!-- Commented out to prevent this dream from appearing in the list of
+ dreams that the user can select via the Settings application.
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ -->
+ </service>
+ </application>
+</manifest>
diff --git a/tests/DozeTest/res/drawable-hdpi/ic_app.png b/tests/DozeTest/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/DozeTest/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/drawable-mdpi/ic_app.png b/tests/DozeTest/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/DozeTest/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/layout/dream.xml b/tests/DozeTest/res/layout/dream.xml
new file mode 100644
index 0000000..1c8fd3f
--- /dev/null
+++ b/tests/DozeTest/res/layout/dream.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/alarm_clock_label" />
+ <TextView android:id="@+id/alarm_clock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/tick_clock_label" />
+ <TextClock android:id="@+id/tick_clock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/DozeTest/res/values/strings.xml b/tests/DozeTest/res/values/strings.xml
new file mode 100644
index 0000000..f21911f
--- /dev/null
+++ b/tests/DozeTest/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+ <!-- Name of the package of basic screensavers, shown in Settings > Apps. [CHAR LIMIT=40] -->
+ <string name="app_name">Doze Test</string>
+
+ <!-- Name of the screensaver. [CHAR LIMIT=40] -->
+ <string name="doze_dream_name">Doze Test</string>
+
+ <string name="alarm_clock_label">This clock is updated using the Alarm Manager</string>
+ <string name="tick_clock_label">This clock is updated using TIME_TICK Broadcasts</string>
+</resources>
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
new file mode 100644
index 0000000..bf35db4
--- /dev/null
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -0,0 +1,165 @@
+/*
+ * 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 com.android.dreams.dozetest;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.service.dreams.DozeHardware;
+import android.service.dreams.DreamService;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.widget.TextView;
+
+import java.util.Date;
+
+/**
+ * Simple test for doze mode.
+ * <p>
+ * adb shell setprop debug.doze.component com.android.dreams.dozetest/.DozeTestDream
+ * </p>
+ */
+public class DozeTestDream extends DreamService {
+ private static final String TAG = DozeTestDream.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ // Amount of time to allow to update the time shown on the screen before releasing
+ // the wakelock. This timeout is design to compensate for the fact that we don't
+ // currently have a way to know when time display contents have actually been
+ // refreshed once the dream has finished rendering a new frame.
+ private static final int UPDATE_TIME_TIMEOUT = 100;
+
+ // A doze hardware message string we use for end-to-end testing.
+ // Doesn't mean anything. Real hardware won't handle it.
+ private static final String TEST_PING_MESSAGE = "test.ping";
+
+ private PowerManager mPowerManager;
+ private PowerManager.WakeLock mWakeLock;
+ private AlarmManager mAlarmManager;
+ private PendingIntent mAlarmIntent;
+
+ private TextView mAlarmClock;
+
+ private final Date mTime = new Date();
+ private java.text.DateFormat mTimeFormat;
+
+ private boolean mDreaming;
+ private DozeHardware mDozeHardware;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ mAlarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
+
+ Intent intent = new Intent("com.android.dreams.dozetest.ACTION_ALARM");
+ intent.setPackage(getPackageName());
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(intent.getAction());
+ registerReceiver(mAlarmReceiver, filter);
+ mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ unregisterReceiver(mAlarmReceiver);
+ mAlarmIntent.cancel();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setInteractive(false);
+ setLowProfile(true);
+ setFullscreen(true);
+ setContentView(R.layout.dream);
+
+ mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
+
+ mTimeFormat = DateFormat.getTimeFormat(this);
+ }
+
+ @Override
+ public void onDreamingStarted() {
+ super.onDreamingStarted();
+
+ mDreaming = true;
+ mDozeHardware = getDozeHardware();
+
+ Log.d(TAG, "Dream started: canDoze=" + canDoze()
+ + ", dozeHardware=" + mDozeHardware);
+
+ performTimeUpdate();
+
+ if (mDozeHardware != null) {
+ mDozeHardware.sendMessage(TEST_PING_MESSAGE, null);
+ mDozeHardware.setEnableMcu(true);
+ }
+ startDozing();
+ }
+
+ @Override
+ public void onDreamingStopped() {
+ super.onDreamingStopped();
+
+ mDreaming = false;
+ if (mDozeHardware != null) {
+ mDozeHardware.setEnableMcu(false);
+ mDozeHardware = null;
+ }
+
+ Log.d(TAG, "Dream ended: isDozing=" + isDozing());
+
+ stopDozing();
+ cancelTimeUpdate();
+ }
+
+ private void performTimeUpdate() {
+ if (mDreaming) {
+ long now = System.currentTimeMillis();
+ now -= now % 60000; // back up to last minute boundary
+
+ mTime.setTime(now);
+ mAlarmClock.setText(mTimeFormat.format(mTime));
+
+ mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, now + 60000, mAlarmIntent);
+
+ mWakeLock.acquire(UPDATE_TIME_TIMEOUT);
+ }
+ }
+
+ private void cancelTimeUpdate() {
+ mAlarmManager.cancel(mAlarmIntent);
+ }
+
+ private final BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ performTimeUpdate();
+ }
+ };
+}