Merge "Expose an API to generate a badged icon for managed profiles."
diff --git a/api/current.txt b/api/current.txt
index 9683990..2eea8ac 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35,6 +35,7 @@
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
+ field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
field public static final java.lang.String BRICK = "android.permission.BRICK";
field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
@@ -2456,6 +2457,7 @@
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
+ method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
@@ -4755,6 +4757,7 @@
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
+ method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
@@ -4953,6 +4956,7 @@
method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
method public void setPasswordQuality(android.content.ComponentName, int);
+ method public void setProfileEnabled(android.content.ComponentName);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void wipeData(int);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
@@ -7781,6 +7785,7 @@
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
+ method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public abstract java.lang.String getNameForUid(int);
method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11394,10 +11399,33 @@
method public int getMinDelay();
method public java.lang.String getName();
method public float getPower();
+ method public java.lang.String getRequiredPermission();
method public float getResolution();
+ method public java.lang.String getStringType();
method public int getType();
method public java.lang.String getVendor();
method public int getVersion();
+ field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+ field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+ field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
+ field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
+ field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+ field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+ field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+ field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+ field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
+ field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
+ field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+ field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+ field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+ field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+ field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+ field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+ field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+ field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+ field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+ field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+ field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
field public static final int TYPE_ACCELEROMETER = 1; // 0x1
field public static final int TYPE_ALL = -1; // 0xffffffff
field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -11406,6 +11434,7 @@
field public static final int TYPE_GRAVITY = 9; // 0x9
field public static final int TYPE_GYROSCOPE = 4; // 0x4
field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+ field public static final int TYPE_HEART_RATE = 21; // 0x15
field public static final int TYPE_LIGHT = 5; // 0x5
field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
@@ -12158,6 +12187,7 @@
public final class HdmiCecClient {
method public boolean isTvOn();
method public void sendActiveSource();
+ method public void sendGiveDevicePowerStatus(int);
method public void sendImageViewOn();
method public void sendInactiveSource();
method public void sendTextViewOn();
@@ -19735,7 +19765,8 @@
public final class PowerManager {
method public void goToSleep(long);
- method public boolean isScreenOn();
+ method public boolean isInteractive();
+ method public deprecated boolean isScreenOn();
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
method public void userActivity(long, boolean);
@@ -24807,7 +24838,7 @@
method public abstract void onUtteranceCompleted(java.lang.String);
}
- public final class TextToSpeechClient {
+ public class TextToSpeechClient {
ctor public TextToSpeechClient(android.content.Context, java.lang.String, boolean, android.speech.tts.TextToSpeechClient.RequestCallbacks, android.speech.tts.TextToSpeechClient.ConnectionCallbacks);
ctor public TextToSpeechClient(android.content.Context, android.speech.tts.TextToSpeechClient.RequestCallbacks, android.speech.tts.TextToSpeechClient.ConnectionCallbacks);
method public void connect();
@@ -26001,6 +26032,7 @@
method public java.lang.String getInstallerPackageName(java.lang.String);
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
+ method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -28413,6 +28445,7 @@
method public float getRefreshRate();
method public int getRotation();
method public void getSize(android.graphics.Point);
+ method public int getState();
method public deprecated int getWidth();
method public boolean isValid();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
@@ -28420,6 +28453,10 @@
field public static final int FLAG_PRIVATE = 4; // 0x4
field public static final int FLAG_SECURE = 2; // 0x2
field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
+ field public static final int STATE_DOZING = 3; // 0x3
+ field public static final int STATE_OFF = 1; // 0x1
+ field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_UNKNOWN = 0; // 0x0
}
public class DragEvent implements android.os.Parcelable {
@@ -28765,7 +28802,7 @@
field public static final int FLAG_SOFT_KEYBOARD = 2; // 0x2
field public static final int FLAG_TRACKING = 512; // 0x200
field public static final int FLAG_VIRTUAL_HARD_KEY = 64; // 0x40
- field public static final int FLAG_WOKE_HERE = 1; // 0x1
+ field public static final deprecated int FLAG_WOKE_HERE = 1; // 0x1
field public static final int KEYCODE_0 = 7; // 0x7
field public static final int KEYCODE_1 = 8; // 0x8
field public static final int KEYCODE_2 = 9; // 0x9
@@ -30899,7 +30936,7 @@
field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
- field public static final int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
+ field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 3e8d6a0..c520b58 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -138,8 +138,10 @@
#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
+static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
+static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif
int main(int argc, char* const argv[])
@@ -185,16 +187,19 @@
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
- niceName = "zygote";
+ niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName = arg + 12;
- } else {
+ } else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
+ } else {
+ --i;
+ break;
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index b01d92c..2620c44 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -526,6 +526,31 @@
}
/**
+ * Find the view that has the specified focus type. The search is performed
+ * across all windows.
+ * <p>
+ * <strong>Note:</strong> In order to access the windows your service has
+ * to declare the capability to retrieve window content by setting the
+ * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
+ * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
+ * Also the service has to opt-in to retrieve the interactive windows by
+ * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
+ * flag.Otherwise, the search will be performed only in the active window.
+ * </p>
+ *
+ * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+ * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+ * @return The node info of the focused view or null.
+ *
+ * @see AccessibilityNodeInfo#FOCUS_INPUT
+ * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
+ */
+ public AccessibilityNodeInfo findFocus(int focus) {
+ return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
+ AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
+ }
+
+ /**
* Gets the an {@link AccessibilityServiceInfo} describing this
* {@link AccessibilityService}. This method is useful if one wants
* to change some of the dynamically configurable properties at
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
new file mode 100644
index 0000000..f9af979
--- /dev/null
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -0,0 +1,116 @@
+/*
+ * 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide Retrieves information from an ALSA "cards" file.
+ */
+public class AlsaCardsParser {
+ private static final String TAG = "AlsaCardsParser";
+
+ private static LineTokenizer tokenizer_ = new LineTokenizer(" :[]");
+
+ public class AlsaCardRecord {
+ public int mCardNum = -1;
+ public String mField1 = "";
+ public String mCardName = "";
+ public String mCardDescription = "";
+
+ public AlsaCardRecord() {}
+
+ public boolean parse(String line, int lineIndex) {
+ int tokenIndex = 0;
+ int delimIndex = 0;
+ if (lineIndex == 0) {
+ // line # (skip)
+ tokenIndex = tokenizer_.nextToken(line, tokenIndex);
+ delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+
+ // mField1
+ tokenIndex = tokenizer_.nextToken(line, delimIndex);
+ delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+ mField1 = line.substring(tokenIndex, delimIndex);
+
+ // mCardName
+ tokenIndex = tokenizer_.nextToken(line, delimIndex);
+ // delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+ mCardName = line.substring(tokenIndex);
+ // done
+ } else if (lineIndex == 1) {
+ tokenIndex = tokenizer_.nextToken(line, 0);
+ if (tokenIndex != -1) {
+ mCardDescription = line.substring(tokenIndex);
+ }
+ }
+
+ return true;
+ }
+
+ public String textFormat() {
+ return mCardName + " : " + mCardDescription;
+ }
+ }
+
+ private Vector<AlsaCardRecord> cardRecords_ = new Vector<AlsaCardRecord>();
+
+ public void scan() {
+ cardRecords_.clear();
+ final String cardsFilePath = "/proc/asound/cards";
+ File cardsFile = new File(cardsFilePath);
+ try {
+ FileReader reader = new FileReader(cardsFile);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String line = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ AlsaCardRecord cardRecord = new AlsaCardRecord();
+ cardRecord.parse(line, 0);
+ cardRecord.parse(line = bufferedReader.readLine(), 1);
+ cardRecords_.add(cardRecord);
+ }
+ reader.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public AlsaCardRecord getCardRecordAt(int index) {
+ return cardRecords_.get(index);
+ }
+
+ public int getNumCardRecords() {
+ return cardRecords_.size();
+ }
+
+ public void Log() {
+ int numCardRecs = getNumCardRecords();
+ for (int index = 0; index < numCardRecs; ++index) {
+ Slog.w(TAG, "usb:" + getCardRecordAt(index).textFormat());
+ }
+ }
+
+ public AlsaCardsParser() {}
+}
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
new file mode 100644
index 0000000..094c8a2
--- /dev/null
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -0,0 +1,275 @@
+/*
+ * 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide
+ * Retrieves information from an ALSA "devices" file.
+ */
+public class AlsaDevicesParser {
+ private static final String TAG = "AlsaDevicesParser";
+
+ private static final int kIndex_CardDeviceField = 5;
+ private static final int kStartIndex_CardNum = 6;
+ private static final int kEndIndex_CardNum = 8; // one past
+ private static final int kStartIndex_DeviceNum = 9;
+ private static final int kEndIndex_DeviceNum = 11; // one past
+ private static final int kStartIndex_Type = 14;
+
+ private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
+
+ private boolean mHasCaptureDevices = false;
+ private boolean mHasPlaybackDevices = false;
+ private boolean mHasMIDIDevices = false;
+
+ public class AlsaDeviceRecord {
+ public static final int kDeviceType_Unknown = -1;
+ public static final int kDeviceType_Audio = 0;
+ public static final int kDeviceType_Control = 1;
+ public static final int kDeviceType_MIDI = 2;
+
+ public static final int kDeviceDir_Unknown = -1;
+ public static final int kDeviceDir_Capture = 0;
+ public static final int kDeviceDir_Playback = 1;
+
+ int mCardNum = -1;
+ int mDeviceNum = -1;
+ int mDeviceType = kDeviceType_Unknown;
+ int mDeviceDir = kDeviceDir_Unknown;
+
+ public AlsaDeviceRecord() {
+ }
+
+ public boolean parse(String line) {
+ // "0123456789012345678901234567890"
+ // " 2: [ 0-31]: digital audio playback"
+ // " 3: [ 0-30]: digital audio capture"
+ // " 35: [ 1] : control"
+ // " 36: [ 2- 0]: raw midi"
+
+ final int kToken_LineNum = 0;
+ final int kToken_CardNum = 1;
+ final int kToken_DeviceNum = 2;
+ final int kToken_Type0 = 3; // "digital", "control", "raw"
+ final int kToken_Type1 = 4; // "audio", "midi"
+ final int kToken_Type2 = 5; // "capture", "playback"
+
+ int tokenOffset = 0;
+ int delimOffset = 0;
+ int tokenIndex = kToken_LineNum;
+ while (true) {
+ tokenOffset = mTokenizer.nextToken(line, delimOffset);
+ if (tokenOffset == LineTokenizer.kTokenNotFound) {
+ break; // bail
+ }
+ delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
+ if (delimOffset == LineTokenizer.kTokenNotFound) {
+ delimOffset = line.length();
+ }
+ String token = line.substring(tokenOffset, delimOffset);
+
+ switch (tokenIndex) {
+ case kToken_LineNum:
+ // ignore
+ break;
+
+ case kToken_CardNum:
+ mCardNum = Integer.parseInt(token);
+ if (line.charAt(delimOffset) != '-') {
+ tokenIndex++; // no device # in the token stream
+ }
+ break;
+
+ case kToken_DeviceNum:
+ mDeviceNum = Integer.parseInt(token);
+ break;
+
+ case kToken_Type0:
+ if (token.equals("digital")) {
+ // NOP
+ } else if (token.equals("control")) {
+ mDeviceType = kDeviceType_Control;
+ } else if (token.equals("raw")) {
+ // NOP
+ }
+ break;
+
+ case kToken_Type1:
+ if (token.equals("audio")) {
+ mDeviceType = kDeviceType_Audio;
+ } else if (token.equals("midi")) {
+ mDeviceType = kDeviceType_MIDI;
+ mHasMIDIDevices = true;
+ }
+ break;
+
+ case kToken_Type2:
+ if (token.equals("capture")) {
+ mDeviceDir = kDeviceDir_Capture;
+ mHasCaptureDevices = true;
+ } else if (token.equals("playback")) {
+ mDeviceDir = kDeviceDir_Playback;
+ mHasPlaybackDevices = true;
+ }
+ break;
+ } // switch (tokenIndex)
+
+ tokenIndex++;
+ } // while (true)
+
+ return true;
+ } // parse()
+
+ public String textFormat() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
+
+ switch (mDeviceType) {
+ case kDeviceType_Unknown:
+ sb.append(" N/A");
+ break;
+ case kDeviceType_Audio:
+ sb.append(" Audio");
+ break;
+ case kDeviceType_Control:
+ sb.append(" Control");
+ break;
+ case kDeviceType_MIDI:
+ sb.append(" MIDI");
+ break;
+ }
+
+ switch (mDeviceDir) {
+ case kDeviceDir_Unknown:
+ sb.append(" N/A");
+ break;
+ case kDeviceDir_Capture:
+ sb.append(" Capture");
+ break;
+ case kDeviceDir_Playback:
+ sb.append(" Playback");
+ break;
+ }
+
+ return sb.toString();
+ }
+ }
+
+ private Vector<AlsaDeviceRecord>
+ deviceRecords_ = new Vector<AlsaDeviceRecord>();
+
+ private boolean isLineDeviceRecord(String line) {
+ return line.charAt(kIndex_CardDeviceField) == '[';
+ }
+
+ public AlsaDevicesParser() {
+ }
+
+ public int getNumDeviceRecords() {
+ return deviceRecords_.size();
+ }
+
+ public AlsaDeviceRecord getDeviceRecordAt(int index) {
+ return deviceRecords_.get(index);
+ }
+
+ public void Log() {
+ int numDevRecs = getNumDeviceRecords();
+ for (int index = 0; index < numDevRecs; ++index) {
+ Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat());
+ }
+ }
+
+ public boolean hasPlaybackDevices() {
+ return mHasPlaybackDevices;
+ }
+
+ public boolean hasPlaybackDevices(int card) {
+ for (int index = 0; index < deviceRecords_.size(); index++) {
+ AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+ if (deviceRecord.mCardNum == card &&
+ deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+ deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasCaptureDevices() {
+ return mHasCaptureDevices;
+ }
+
+ public boolean hasCaptureDevices(int card) {
+ for (int index = 0; index < deviceRecords_.size(); index++) {
+ AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+ if (deviceRecord.mCardNum == card &&
+ deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+ deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasMIDIDevices() {
+ return mHasMIDIDevices;
+ }
+
+ public boolean hasMIDIDevices(int card) {
+ for (int index = 0; index < deviceRecords_.size(); index++) {
+ AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+ if (deviceRecord.mCardNum == card &&
+ deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void scan() {
+ deviceRecords_.clear();
+
+ final String devicesFilePath = "/proc/asound/devices";
+ File devicesFile = new File(devicesFilePath);
+ try {
+ FileReader reader = new FileReader(devicesFile);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String line = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ if (isLineDeviceRecord(line)) {
+ AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
+ deviceRecord.parse(line);
+ deviceRecords_.add(deviceRecord);
+ }
+ }
+ reader.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+} // class AlsaDevicesParser
+
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
new file mode 100644
index 0000000..c138fc5
--- /dev/null
+++ b/core/java/android/alsa/LineTokenizer.java
@@ -0,0 +1,57 @@
+/*
+ * 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.alsascan;
+
+/**
+ * @hide
+ * Breaks lines in an ALSA "cards" or "devices" file into tokens.
+ * TODO(pmclean) Look into replacing this with String.split().
+ */
+public class LineTokenizer {
+ public static final int kTokenNotFound = -1;
+
+ private String mDelimiters = "";
+
+ public LineTokenizer(String delimiters) {
+ mDelimiters = delimiters;
+ }
+
+ int nextToken(String line, int startIndex) {
+ int len = line.length();
+ int offset = startIndex;
+ for (; offset < len; offset++) {
+ if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
+ // past a delimiter
+ break;
+ }
+ }
+
+ return offset < len ? offset : kTokenNotFound;
+ }
+
+ int nextDelimiter(String line, int startIndex) {
+ int len = line.length();
+ int offset = startIndex;
+ for (; offset < len; offset++) {
+ if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
+ // past a delimiter
+ break;
+ }
+ }
+
+ return offset < len ? offset : kTokenNotFound;
+ }
+}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6ca5244..ab62427 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -128,6 +128,24 @@
}
@Override
+ public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+ // Try to find a main leanback_launcher activity.
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+ intentToResolve.setPackage(packageName);
+ List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
+
+ if (ris == null || ris.size() <= 0) {
+ return null;
+ }
+ Intent intent = new Intent(intentToResolve);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setClassName(ris.get(0).activityInfo.packageName,
+ ris.get(0).activityInfo.name);
+ return intent;
+ }
+
+ @Override
public int[] getPackageGids(String packageName)
throws NameNotFoundException {
try {
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 8523d0c..9405325 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -297,6 +297,28 @@
}
/**
+ * Find the view that has the specified focus type. The search is performed
+ * across all windows.
+ * <p>
+ * <strong>Note:</strong> In order to access the windows you have to opt-in
+ * to retrieve the interactive windows by setting the
+ * {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
+ * Otherwise, the search will be performed only in the active window.
+ * </p>
+ *
+ * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+ * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+ * @return The node info of the focused view or null.
+ *
+ * @see AccessibilityNodeInfo#FOCUS_INPUT
+ * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
+ */
+ public AccessibilityNodeInfo findFocus(int focus) {
+ return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
+ AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
+ }
+
+ /**
* Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
* This method is useful if one wants to change some of the dynamically
* configurable properties at runtime.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d8be439..725f808 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1756,8 +1756,26 @@
}
/**
+ * Sets the enabled state of the profile. A profile should be enabled only once it is ready to
+ * be used. Only the profile owner can call this.
+ *
+ * @see #isPRofileOwnerApp
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ */
+ public void setProfileEnabled(ComponentName admin) {
+ if (mService != null) {
+ try {
+ mService.setProfileEnabled(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
* Used to determine if a particular package is registered as the Profile Owner for the
- * current user. A profile owner is a special device admin that has additional priviledges
+ * current user. A profile owner is a special device admin that has additional privileges
* within the managed profile.
*
* @param packageName The package name of the app to compare with the registered profile owner.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8119585..e4b2adc 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -107,6 +107,7 @@
boolean setProfileOwner(String packageName, String ownerName, int userHandle);
String getProfileOwner(int userHandle);
String getProfileOwnerName(int userHandle);
+ void setProfileEnabled(in ComponentName who);
boolean installCaCert(in byte[] certBuffer);
void uninstallCaCert(in byte[] certBuffer);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9881428..a7d5606 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1417,15 +1417,38 @@
// Standard intent broadcast actions (see action variable).
/**
- * Broadcast Action: Sent after the screen turns off.
+ * Broadcast Action: Sent when the device goes to sleep and becomes non-interactive.
+ * <p>
+ * For historical reasons, the name of this broadcast action refers to the power
+ * state of the screen but it is actually sent in response to changes in the
+ * overall interactive state of the device.
+ * </p><p>
+ * This broadcast is sent when the device becomes non-interactive which may have
+ * nothing to do with the screen turning off. To determine the
+ * actual state of the screen, use {@link android.view.Display#getState}.
+ * </p><p>
+ * See {@link android.os.PowerManager#isInteractive} for details.
+ * </p>
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
+
/**
- * Broadcast Action: Sent after the screen turns on.
+ * Broadcast Action: Sent when the device wakes up and becomes interactive.
+ * <p>
+ * For historical reasons, the name of this broadcast action refers to the power
+ * state of the screen but it is actually sent in response to changes in the
+ * overall interactive state of the device.
+ * </p><p>
+ * This broadcast is sent when the device becomes interactive which may have
+ * nothing to do with the screen turning on. To determine the
+ * actual state of the screen, use {@link android.view.Display#getState}.
+ * </p><p>
+ * See {@link android.os.PowerManager#isInteractive} for details.
+ * </p>
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d24a472..d981cc1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1012,6 +1012,7 @@
* @hide
* @deprecated
*/
+ @Deprecated
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
@@ -1308,6 +1309,7 @@
* something like a DPAD, not through touch or mouse.
* @deprecated use {@link #FEATURE_LEANBACK} instead.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_TELEVISION = "android.hardware.type.television";
@@ -1522,17 +1524,33 @@
public abstract Intent getLaunchIntentForPackage(String packageName);
/**
- * Return an array of all of the secondary group-ids that have been
- * assigned to a package.
- *
- * <p>Throws {@link NameNotFoundException} if a package with the given
- * name cannot be found on the system.
- *
+ * Return a "good" intent to launch a front-door Leanback activity in a
+ * package, for use for example to implement an "open" button when browsing
+ * through packages. The current implementation will look for a main
+ * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
+ * return null if no main leanback activities are found.
+ * <p>
+ * Throws {@link NameNotFoundException} if a package with the given name
+ * cannot be found on the system.
+ *
+ * @param packageName The name of the package to inspect.
+ * @return Returns either a fully-qualified Intent that can be used to launch
+ * the main Leanback activity in the package, or null if the package
+ * does not contain such an activity.
+ */
+ public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
+
+ /**
+ * Return an array of all of the secondary group-ids that have been assigned
+ * to a package.
+ * <p>
+ * Throws {@link NameNotFoundException} if a package with the given name
+ * cannot be found on the system.
+ *
* @param packageName The full name (i.e. com.google.apps.contacts) of the
- * desired package.
- *
- * @return Returns an int array of the assigned gids, or null if there
- * are none.
+ * desired package.
+ * @return Returns an int array of the assigned gids, or null if there are
+ * none.
*/
public abstract int[] getPackageGids(String packageName)
throws NameNotFoundException;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 89a5819..4bea9ee 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -38,6 +38,13 @@
public static final int TYPE_ACCELEROMETER = 1;
/**
+ * A constant string describing an accelerometer sensor type.
+ *
+ * @see #TYPE_ACCELEROMETER
+ */
+ public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+
+ /**
* A constant describing a magnetic field sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -45,6 +52,13 @@
public static final int TYPE_MAGNETIC_FIELD = 2;
/**
+ * A constant string describing a magnetic field sensor type.
+ *
+ * @see #TYPE_MAGNETIC_FIELD
+ */
+ public static final String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+
+ /**
* A constant describing an orientation sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -55,24 +69,58 @@
@Deprecated
public static final int TYPE_ORIENTATION = 3;
- /** A constant describing a gyroscope sensor type.
+ /**
+ * A constant string describing an orientation sensor type.
+ *
+ * @see #TYPE_ORIENTATION
+ * @deprecated use {@link android.hardware.SensorManager#getOrientation
+ * SensorManager.getOrientation()} instead.
+ */
+ @Deprecated
+ public static final String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+
+ /**
+ * A constant describing a gyroscope sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details. */
public static final int TYPE_GYROSCOPE = 4;
/**
+ * A constant string describing a gyroscope sensor type.
+ *
+ * @see #TYPE_GYROSCOPE
+ */
+ public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+
+ /**
* A constant describing a light sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
*/
public static final int TYPE_LIGHT = 5;
- /** A constant describing a pressure sensor type.
+ /**
+ * A constant string describing a light sensor type.
+ *
+ * @see #TYPE_LIGHT
+ */
+ public static final String STRING_TYPE_LIGHT = "android.sensor.light";
+
+ /**
+ * A constant describing a pressure sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
- * for more details. */
+ * for more details.
+ */
public static final int TYPE_PRESSURE = 6;
/**
+ * A constant string describing a pressure sensor type.
+ *
+ * @see #TYPE_PRESSURE
+ */
+ public static final String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+
+ /**
* A constant describing a temperature sensor type
*
* @deprecated use
@@ -83,6 +131,17 @@
public static final int TYPE_TEMPERATURE = 7;
/**
+ * A constant string describing a temperature sensor type
+ *
+ * @see #TYPE_TEMPERATURE
+ * @deprecated use
+ * {@link android.hardware.Sensor#STRING_TYPE_AMBIENT_TEMPERATURE
+ * Sensor.STRING_TYPE_AMBIENT_TEMPERATURE} instead.
+ */
+ @Deprecated
+ public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+
+ /**
* A constant describing a proximity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -90,6 +149,13 @@
public static final int TYPE_PROXIMITY = 8;
/**
+ * A constant string describing a proximity sensor type.
+ *
+ * @see #TYPE_PROXIMITY
+ */
+ public static final String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+
+ /**
* A constant describing a gravity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -97,6 +163,13 @@
public static final int TYPE_GRAVITY = 9;
/**
+ * A constant string describing a gravity sensor type.
+ *
+ * @see #TYPE_GRAVITY
+ */
+ public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+
+ /**
* A constant describing a linear acceleration sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -104,6 +177,14 @@
public static final int TYPE_LINEAR_ACCELERATION = 10;
/**
+ * A constant string describing a linear acceleration sensor type.
+ *
+ * @see #TYPE_LINEAR_ACCELERATION
+ */
+ public static final String STRING_TYPE_LINEAR_ACCELERATION =
+ "android.sensor.linear_acceleration";
+
+ /**
* A constant describing a rotation vector sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
@@ -111,18 +192,42 @@
public static final int TYPE_ROTATION_VECTOR = 11;
/**
+ * A constant string describing a rotation vector sensor type.
+ *
+ * @see #TYPE_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+
+ /**
* A constant describing a relative humidity sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
* for more details.
*/
public static final int TYPE_RELATIVE_HUMIDITY = 12;
- /** A constant describing an ambient temperature sensor type.
+ /**
+ * A constant string describing a relative humidity sensor type
+ *
+ * @see #TYPE_RELATIVE_HUMIDITY
+ */
+ public static final String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+
+ /**
+ * A constant describing an ambient temperature sensor type.
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
- * for more details. */
+ * for more details.
+ */
public static final int TYPE_AMBIENT_TEMPERATURE = 13;
/**
+ * A constant string describing an ambient temperature sensor type.
+ *
+ * @see #TYPE_AMBIENT_TEMPERATURE
+ */
+ public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
+ "android.sensor.ambient_temperature";
+
+ /**
* A constant describing an uncalibrated magnetic field sensor type.
* <p>
* Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (device calibration
@@ -139,6 +244,13 @@
* details.
*/
public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
+ /**
+ * A constant string describing an uncalibrated magnetic field sensor type.
+ *
+ * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
+ */
+ public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
+ "android.sensor.magnetic_field_uncalibrated";
/**
* A constant describing an uncalibrated rotation vector sensor type.
@@ -156,10 +268,17 @@
* <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more
* details.
*/
-
public static final int TYPE_GAME_ROTATION_VECTOR = 15;
/**
+ * A constant string describing an uncalibrated rotation vector sensor type.
+ *
+ * @see #TYPE_GAME_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
+ "android.sensor.game_rotation_vector";
+
+ /**
* A constant describing an uncalibrated gyroscope sensor type.
* <p>Similar to {@link #TYPE_GYROSCOPE} but no gyro-drift compensation has been performed
* to adjust the given sensor values. However, such gyro-drift bias values
@@ -174,6 +293,14 @@
public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
/**
+ * A constant string describing an uncalibrated gyroscope sensor type.
+ *
+ * @see #TYPE_GYROSCOPE_UNCALIBRATED
+ */
+ public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
+ "android.sensor.gyroscope_uncalibrated";
+
+ /**
* A constant describing a significant motion trigger sensor.
* <p>
* It triggers when an event occurs and then automatically disables
@@ -186,6 +313,14 @@
public static final int TYPE_SIGNIFICANT_MOTION = 17;
/**
+ * A constant string describing a significant motion trigger sensor.
+ *
+ * @see #TYPE_SIGNIFICANT_MOTION
+ */
+ public static final String STRING_TYPE_SIGNIFICANT_MOTION =
+ "android.sensor.significant_motion";
+
+ /**
* A constant describing a step detector sensor.
* <p>
* A sensor of this type triggers an event each time a step is taken by the user. The only
@@ -198,6 +333,13 @@
public static final int TYPE_STEP_DETECTOR = 18;
/**
+ * A constant string describing a step detector sensor.
+ *
+ * @see #TYPE_STEP_DETECTOR
+ */
+ public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+
+ /**
* A constant describing a step counter sensor.
* <p>
* A sensor of this type returns the number of steps taken by the user since the last reboot
@@ -211,7 +353,14 @@
public static final int TYPE_STEP_COUNTER = 19;
/**
- * A constant describing the geo-magnetic rotation vector.
+ * A constant string describing a step counter sensor.
+ *
+ * @see #TYPE_STEP_COUNTER
+ */
+ public static final String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+
+ /**
+ * A constant describing a geo-magnetic rotation vector.
* <p>
* Similar to {@link #TYPE_ROTATION_VECTOR}, but using a magnetometer instead of using a
* gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
@@ -222,6 +371,32 @@
public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
/**
+ * A constant string describing a geo-magnetic rotation vector.
+ *
+ * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ */
+ public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
+ "android.sensor.geomagnetic_rotation_vector";
+
+ /**
+ * A constant describing a heart rate monitor.
+ * <p>
+ * A sensor that measures the heart rate in beats per minute.
+ * <p>
+ * value[0] represents the beats per minute when the measurement was taken.
+ * value[0] is 0 if the heart rate monitor could not measure the rate or the
+ * rate is 0 beat per minute.
+ */
+ public static final int TYPE_HEART_RATE = 21;
+
+ /**
+ * A constant string describing a heart rate monitor.
+ *
+ * @see #TYPE_HEART_RATE
+ */
+ public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+
+ /**
* A constant describing all sensor types.
*/
public static final int TYPE_ALL = -1;
@@ -265,7 +440,8 @@
// added post 4.3
REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_DETECTOR
REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_COUNTER
- REPORTING_MODE_CONTINUOUS, 5 // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ REPORTING_MODE_ON_CHANGE, 1 // SENSOR_TYPE_HEART_RATE_MONITOR
};
static int getReportingMode(Sensor sensor) {
@@ -321,6 +497,8 @@
private int mMinDelay;
private int mFifoReservedEventCount;
private int mFifoMaxEventCount;
+ private String mStringType;
+ private String mRequiredPermission;
Sensor() {
}
@@ -401,6 +579,20 @@
return mFifoMaxEventCount;
}
+ /**
+ * @return The type of this sensor as a string.
+ */
+ public String getStringType() {
+ return mStringType;
+ }
+
+ /**
+ * @return The permission required to access this sensor. If empty, no permission is required.
+ */
+ public String getRequiredPermission() {
+ return mRequiredPermission;
+ }
+
/** @hide */
public int getHandle() {
return mHandle;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 03fa1d5..cec90cd 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -58,16 +58,6 @@
public abstract boolean isProximitySensorAvailable();
/**
- * Called by the power manager to blank all displays.
- */
- public abstract void blankAllDisplaysFromPowerManager();
-
- /**
- * Called by the power manager to unblank all displays.
- */
- public abstract void unblankAllDisplaysFromPowerManager();
-
- /**
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
@@ -254,12 +244,10 @@
void onStateChanged();
void onProximityPositive();
void onProximityNegative();
+ void onDisplayStateChange(int state); // one of the Display state constants
void acquireSuspendBlocker();
void releaseSuspendBlocker();
-
- void blankAllDisplays();
- void unblankAllDisplays();
}
/**
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
index 1f382e6..cd86cd8 100644
--- a/core/java/android/hardware/hdmi/HdmiCecClient.java
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -88,7 +88,7 @@
}
/**
- * Send <TextViewOn> message.
+ * Send <Text View On> message.
*/
public void sendTextViewOn() {
try {
@@ -99,7 +99,7 @@
}
/**
- * Send <ImageViewOn> message.
+ * Send <Image View On> message.
*/
public void sendImageViewOn() {
try {
@@ -110,6 +110,20 @@
}
/**
+ * Send <Give Device Power Status> message.
+ *
+ * @param address logical address of the device to send the message to, such as
+ * {@link HdmiCec#ADDR_TV}.
+ */
+ public void sendGiveDevicePowerStatus(int address) {
+ try {
+ mService.sendGiveDevicePowerStatus(mBinder, address);
+ } catch (RemoteException e) {
+ Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+ }
+ }
+
+ /**
* Returns true if the TV or attached display is powered on.
* <p>
* The result of this method is only meaningful on playback devices (where the device
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
index b5df131..ecdd345 100644
--- a/core/java/android/hardware/hdmi/IHdmiCecService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -33,6 +33,7 @@
void sendInactiveSource(IBinder b);
void sendImageViewOn(IBinder b);
void sendTextViewOn(IBinder b);
+ void sendGiveDevicePowerStatus(IBinder b, int address);
boolean isTvOn(IBinder b);
void sendMessage(IBinder b, in HdmiCecMessage message);
}
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 8be94d0..6a392dd 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -25,12 +25,18 @@
* @hide Only for use within the system server.
*/
public abstract class InputManagerInternal {
+ public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+
/**
- * Sets information about the displays as needed by the input system.
- * The input system should copy this information if required.
+ * Called by the display manager to set information about the displays as needed
+ * by the input system. The input system must copy this information to retain it.
*/
public abstract void setDisplayViewports(DisplayViewport defaultViewport,
DisplayViewport externalTouchViewport);
- public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+ /**
+ * Called by the power manager to tell the input manager whether it should start
+ * watching for wake events.
+ */
+ public abstract void setInteractive(boolean interactive);
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index be3c0cc..6c7b08d 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -40,8 +40,8 @@
void wakeUp(long time);
void goToSleep(long time, int reason);
void nap(long time);
+ boolean isInteractive();
- boolean isScreenOn();
void reboot(boolean confirm, String reason, boolean wait);
void shutdown(boolean confirm, boolean wait);
void crash(String message);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a195200..f8d7c3e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -601,21 +601,64 @@
}
/**
- * Returns whether the screen is currently on.
+ * Returns true if the device is in an interactive state.
* <p>
- * Only indicates whether the screen is on. The screen could be either bright or dim.
+ * For historical reasons, the name of this method refers to the power state of
+ * the screen but it actually describes the overall interactive state of
+ * the device. This method has been replaced by {@link #isInteractive}.
* </p><p>
- * {@samplecode
- * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- * boolean isScreenOn = pm.isScreenOn();
- * }
+ * The value returned by this method only indicates whether the device is
+ * in an interactive state which may have nothing to do with the screen being
+ * on or off. To determine the actual state of the screen,
+ * use {@link android.view.Display#getState}.
* </p>
*
- * @return whether the screen is on (bright or dim).
+ * @return True if the device is in an interactive state.
+ *
+ * @deprecated Use {@link #isInteractive} instead.
*/
+ @Deprecated
public boolean isScreenOn() {
+ return isInteractive();
+ }
+
+ /**
+ * Returns true if the device is in an interactive state.
+ * <p>
+ * When this method returns true, the device is awake and ready to interact
+ * with the user (although this is not a guarantee that the user is actively
+ * interacting with the device just this moment). The main screen is usually
+ * turned on while in this state. Certain features, such as the proximity
+ * sensor, may temporarily turn off the screen while still leaving the device in an
+ * interactive state. Note in particular that the device is still considered
+ * to be interactive while dreaming (since dreams can be interactive) but not
+ * when it is dozing or asleep.
+ * </p><p>
+ * When this method returns false, the device is dozing or asleep and must
+ * be awoken before it will become ready to interact with the user again. The
+ * main screen is usually turned off while in this state. Certain features,
+ * such as "ambient mode" may cause the main screen to remain on (albeit in a
+ * low power state) to display system-provided content while the device dozes.
+ * </p><p>
+ * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on}
+ * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast
+ * whenever the interactive state of the device changes. For historical reasons,
+ * the names of these broadcasts refer to the power state of the screen
+ * but they are actually sent in response to changes in the overall interactive
+ * state of the device, as described by this method.
+ * </p><p>
+ * Services may use the non-interactive state as a hint to conserve power
+ * since the user is not present.
+ * </p>
+ *
+ * @return True if the device is in an interactive state.
+ *
+ * @see android.content.Intent#ACTION_SCREEN_ON
+ * @see android.content.Intent#ACTION_SCREEN_OFF
+ */
+ public boolean isInteractive() {
try {
- return mService.isScreenOn();
+ return mService.isInteractive();
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index c947eda..995e396 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -372,7 +372,7 @@
for (int i = 0; i < tries; i++) {
if (i > 0) {
try {
- Log.i("Zygote", "Zygote not up yet, sleeping...");
+ Log.i(LOG_TAG, "Zygote not up yet, sleeping...");
Thread.sleep(ZYGOTE_RETRY_MILLIS);
} catch (InterruptedException ex) {
throw new ZygoteStartFailedEx(ex);
@@ -707,6 +707,16 @@
return primaryZygoteState;
}
+ // TODO: Get rid of this. This is a temporary workaround until all the
+ // compilation related pieces for the dual zygote stack are ready.
+ // b/3647418.
+ if (System.getenv("ANDROID_SOCKET_" + SECONDARY_ZYGOTE_SOCKET) == null) {
+ Log.e(LOG_TAG, "Forcing app to primary zygote, secondary unavailable (ABI= " + abi + ")");
+ // Should be :
+ // throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
+ return primaryZygoteState;
+ }
+
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET,
diff --git a/core/java/android/provider/SearchIndexableData.java b/core/java/android/provider/SearchIndexableData.java
index 05285a3..3f88f18 100644
--- a/core/java/android/provider/SearchIndexableData.java
+++ b/core/java/android/provider/SearchIndexableData.java
@@ -128,4 +128,44 @@
locale = Locale.getDefault();
enabled = true;
}
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SearchIndexableData[context: ");
+ sb.append(context);
+ sb.append(", ");
+ sb.append("locale: ");
+ sb.append(locale);
+ sb.append(", ");
+ sb.append("enabled: ");
+ sb.append(enabled);
+ sb.append(", ");
+ sb.append("rank: ");
+ sb.append(rank);
+ sb.append(", ");
+ sb.append("key: ");
+ sb.append(key);
+ sb.append(", ");
+ sb.append("className: ");
+ sb.append(className);
+ sb.append(", ");
+ sb.append("packageName: ");
+ sb.append(packageName);
+ sb.append(", ");
+ sb.append("iconResId: ");
+ sb.append(iconResId);
+ sb.append(", ");
+ sb.append("intentAction: ");
+ sb.append(intentAction);
+ sb.append(", ");
+ sb.append("intentTargetPackage: ");
+ sb.append(intentTargetPackage);
+ sb.append(", ");
+ sb.append("intentTargetClass: ");
+ sb.append(intentTargetClass);
+ sb.append("]");
+
+ return sb.toString();
+ }
}
diff --git a/core/java/android/provider/SearchIndexableResource.java b/core/java/android/provider/SearchIndexableResource.java
index ba3bd4f..bf33c65 100644
--- a/core/java/android/provider/SearchIndexableResource.java
+++ b/core/java/android/provider/SearchIndexableResource.java
@@ -62,4 +62,17 @@
public SearchIndexableResource(Context context) {
super(context);
}
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SearchIndexableResource[");
+ sb.append(super.toString());
+ sb.append(", ");
+ sb.append("xmlResId: ");
+ sb.append(xmlResId);
+ sb.append("]");
+
+ return sb.toString();
+ }
}
\ No newline at end of file
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index de9eeff..2303d65 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -789,10 +789,20 @@
return;
}
- // start it up
- if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
- mStarted = true;
- onDreamingStarted();
+ // We need to defer calling onDreamingStarted until after onWindowAttached,
+ // which is posted to the handler by addView, so we post onDreamingStarted
+ // to the handler also. Need to watch out here in case detach occurs before
+ // this callback is invoked.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mWindow != null) {
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ mStarted = true;
+ onDreamingStarted();
+ }
+ }
+ });
}
private void safelyFinish() {
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index c6a14f2..10e2073 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -57,7 +57,7 @@
* successful callback is the client usable.
* <p>
* After successful connection, the list of all available voices can be obtained
- * by calling the {@link TextToSpeechClient#getEngineStatus() method. The client can
+ * by calling the {@link TextToSpeechClient#getEngineStatus()} method. The client can
* choose a voice using some custom heuristic and build a {@link RequestConfig} object
* using {@link RequestConfig.Builder}, or can use one of the common heuristics found
* in ({@link RequestConfigHelper}.
@@ -69,7 +69,7 @@
* {@link ConnectionCallbacks#onEngineStatusChange} with new set of available voices as argument.
* In response, the client HAVE to recreate all {@link RequestConfig} instances in use.
*/
-public final class TextToSpeechClient {
+public class TextToSpeechClient {
private static final String TAG = TextToSpeechClient.class.getSimpleName();
private final Object mLock = new Object();
diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java
index 90625d8..90e4177 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/core/java/android/tv/TvInputInfo.java
@@ -87,6 +87,34 @@
return 0;
}
+ @Override
+ public int hashCode() {
+ return mId.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof TvInputInfo)) {
+ return false;
+ }
+
+ TvInputInfo obj = (TvInputInfo) o;
+ return mId.equals(obj.mId)
+ && mService.serviceInfo.packageName.equals(obj.mService.serviceInfo.packageName)
+ && mService.serviceInfo.name.equals(obj.mService.serviceInfo.name);
+ }
+
+ @Override
+ public String toString() {
+ return "TvInputInfo{id=" + mId
+ + ", pkg=" + mService.serviceInfo.packageName
+ + ", service=" + mService.serviceInfo.name + "}";
+ }
+
/**
* Used to package this object into a {@link Parcel}.
*
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index d3f63b4..d7a913d 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -204,6 +204,36 @@
public static final int TYPE_VIRTUAL = 5;
/**
+ * Display state: The display state is unknown.
+ *
+ * @see #getState
+ */
+ public static final int STATE_UNKNOWN = 0;
+
+ /**
+ * Display state: The display is off.
+ *
+ * @see #getState
+ */
+ public static final int STATE_OFF = 1;
+
+ /**
+ * Display state: The display is on.
+ *
+ * @see #getState
+ */
+ public static final int STATE_ON = 2;
+
+ /**
+ * Display state: The display is dozing in a low-power state; it may be showing
+ * system-provided content while the device is in a non-interactive state.
+ *
+ * @see #getState
+ * @see android.os.PowerManager#isInteractive
+ */
+ public static final int STATE_DOZING = 3;
+
+ /**
* Internal method to create a display.
* Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
* or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -630,6 +660,19 @@
}
/**
+ * Gets the state of the display, such as whether it is on or off.
+ *
+ * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
+ * {@link #STATE_DOZING}, or {@link #STATE_UNKNOWN}.
+ */
+ public int getState() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN;
+ }
+ }
+
+ /**
* Returns true if the specified UID has access to this display.
* @hide
*/
@@ -720,5 +763,22 @@
return Integer.toString(type);
}
}
-}
+ /**
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_UNKNOWN:
+ return "UNKNOWN";
+ case STATE_OFF:
+ return "OFF";
+ case STATE_ON:
+ return "ON";
+ case STATE_DOZING:
+ return "DOZING";
+ default:
+ return Integer.toString(state);
+ }
+ }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 7fd7b83..b0fe0fa 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,11 @@
public float physicalYDpi;
/**
+ * The state of the display, such as {@link android.view.Display#STATE_ON}.
+ */
+ public int state;
+
+ /**
* The UID of the application that owns this display, or zero if it is owned by the system.
* <p>
* If the display is private, then only the owner can use it.
@@ -248,6 +253,7 @@
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
+ && state == other.state
&& ownerUid == other.ownerUid
&& Objects.equal(ownerPackageName, other.ownerPackageName);
}
@@ -280,6 +286,7 @@
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
+ state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
}
@@ -307,6 +314,7 @@
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
+ state = source.readInt();
ownerUid = source.readInt();
ownerPackageName = source.readString();
}
@@ -335,6 +343,7 @@
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
+ dest.writeInt(state);
dest.writeInt(ownerUid);
dest.writeString(ownerPackageName);
}
@@ -431,7 +440,7 @@
sb.append(smallestNominalAppHeight);
sb.append(", ");
sb.append(refreshRate);
- sb.append(" fps, rotation");
+ sb.append(" fps, rotation ");
sb.append(rotation);
sb.append(", density ");
sb.append(logicalDensityDpi);
@@ -446,6 +455,8 @@
if (address != null) {
sb.append(", address ").append(address);
}
+ sb.append(", state ");
+ sb.append(Display.stateToString(state));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index c183f08..c3f429c 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1166,7 +1166,11 @@
/**
* This mask is set if the device woke because of this key event.
+ *
+ * @deprecated This flag will never be set by the system since the system
+ * consumes all wake keys itself.
*/
+ @Deprecated
public static final int FLAG_WOKE_HERE = 0x1;
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9761f1a..3c0e6ef 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2968,12 +2968,6 @@
private boolean mLastIsOpaque;
/**
- * Convenience value to check for float values that are close enough to zero to be considered
- * zero.
- */
- private static final float NONZERO_EPSILON = .001f;
-
- /**
* The distance in pixels from the left edge of this view's parent
* to the left edge of this view.
* {@hide}
@@ -8790,11 +8784,6 @@
&& !pointInView(event.getX(), event.getY()))) {
mSendingHoverAccessibilityEvents = false;
sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
- // If the window does not have input focus we take away accessibility
- // focus as soon as the user stop hovering over the view.
- if (mAttachInfo != null && !mAttachInfo.mHasWindowFocus) {
- getViewRootImpl().setAccessibilityFocus(null, null);
- }
}
}
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index b05225b..8eae629 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -27,6 +27,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.AudioService;
import android.media.AudioSystem;
@@ -238,6 +240,7 @@
cleanUp();
}
+ @Override
public void onDismiss(DialogInterface unused) {
mContext.unregisterReceiver(this);
cleanUp();
@@ -259,8 +262,8 @@
mAudioService = volumeService;
// For now, only show master volume if master volume is supported
- boolean useMasterVolume = context.getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume);
+ final boolean useMasterVolume = context.getResources().getBoolean(
+ R.bool.config_useMasterVolume);
if (useMasterVolume) {
for (int i = 0; i < STREAMS.length; i++) {
StreamResources streamRes = STREAMS[i];
@@ -268,10 +271,18 @@
}
}
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View view = mView = inflater.inflate(R.layout.volume_adjust, null);
+ final TypedArray a = context.obtainStyledAttributes(null,
+ com.android.internal.R.styleable.AlertDialog,
+ com.android.internal.R.attr.alertDialogStyle, 0);
+ final Drawable background = a.getDrawable(R.styleable.AlertDialog_fullBright);
+ a.recycle();
+
+ final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mView = inflater.inflate(R.layout.volume_adjust, null);
+ mView.setBackground(background);
mView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
public boolean onTouch(View v, MotionEvent event) {
resetTimeout();
return false;
@@ -279,10 +290,11 @@
});
mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
- mMoreButton = (ImageView) mView.findViewById(R.id.expand_button);
- mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider);
+ mMoreButton = mView.findViewById(R.id.expand_button);
+ mDivider = mView.findViewById(R.id.expand_button_divider);
mDialog = new Dialog(context, R.style.Theme_Panel_Volume) {
+ @Override
public boolean onTouchEvent(MotionEvent event) {
if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
sConfirmSafeVolumeDialog == null) {
@@ -292,22 +304,25 @@
return false;
}
};
+
mDialog.setTitle("Volume control"); // No need to localize
mDialog.setContentView(mView);
mDialog.setOnDismissListener(new OnDismissListener() {
+ @Override
public void onDismiss(DialogInterface dialog) {
mActiveStreamType = -1;
mAudioManager.forceVolumeControlStream(mActiveStreamType);
}
});
+
// Change some window properties
- Window window = mDialog.getWindow();
+ final Window window = mDialog.getWindow();
window.setGravity(Gravity.TOP);
- LayoutParams lp = window.getAttributes();
+
+ final LayoutParams lp = window.getAttributes();
lp.token = null;
// Offset from the top
- lp.y = mContext.getResources().getDimensionPixelOffset(
- com.android.internal.R.dimen.volume_panel_top);
+ lp.y = mContext.getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
lp.width = LayoutParams.WRAP_CONTENT;
lp.height = LayoutParams.WRAP_CONTENT;
@@ -320,6 +335,7 @@
mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
+
// If we don't want to show multiple volumes, hide the settings button and divider
if (!mShowCombinedVolumes) {
mMoreButton.setVisibility(View.GONE);
@@ -328,10 +344,10 @@
mMoreButton.setOnClickListener(this);
}
- boolean masterVolumeOnly = context.getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume);
- boolean masterVolumeKeySounds = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_useVolumeKeySounds);
+ final boolean masterVolumeOnly = context.getResources().getBoolean(
+ R.bool.config_useMasterVolume);
+ final boolean masterVolumeKeySounds = mContext.getResources().getBoolean(
+ R.bool.config_useVolumeKeySounds);
mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
@@ -347,7 +363,7 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
mContext.registerReceiver(new BroadcastReceiver() {
-
+ @Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
@@ -400,17 +416,21 @@
}
private void createSliders() {
- LayoutInflater inflater = (LayoutInflater) mContext
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ final Resources res = mContext.getResources();
+ final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length);
- Resources res = mContext.getResources();
+
for (int i = 0; i < STREAMS.length; i++) {
StreamResources streamRes = STREAMS[i];
- int streamType = streamRes.streamType;
+
+ final int streamType = streamRes.streamType;
if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
streamRes = StreamResources.RingerStream;
}
- StreamControl sc = new StreamControl();
+
+ final StreamControl sc = new StreamControl();
sc.streamType = streamType;
sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
sc.group.setTag(sc);
@@ -421,7 +441,7 @@
sc.iconMuteRes = streamRes.iconMuteRes;
sc.icon.setImageResource(sc.iconRes);
sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
- int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
+ final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
sc.seekbarView.setOnSeekBarChangeListener(this);
@@ -433,7 +453,7 @@
private void reorderSliders(int activeStreamType) {
mSliderGroup.removeAllViews();
- StreamControl active = mStreamControls.get(activeStreamType);
+ final StreamControl active = mStreamControls.get(activeStreamType);
if (active == null) {
Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
mActiveStreamType = -1;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 53a4c0d0..d5a7d33 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -610,7 +610,10 @@
* screen is pressed, you will receive this first touch event. Usually
* the first touch event is consumed by the system since the user can
* not see what they are pressing on.
+ *
+ * @deprecated This flag has no effect.
*/
+ @Deprecated
public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
/** Window flag: as long as this window is visible to the user, keep
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index bd203c8..e68d4c0 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -90,8 +90,7 @@
public final static int FLAG_FILTERED = 0x04000000;
public final static int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
- public final static int FLAG_WOKE_HERE = 0x10000000;
- public final static int FLAG_BRIGHT_HERE = 0x20000000;
+ public final static int FLAG_INTERACTIVE = 0x20000000;
public final static int FLAG_PASS_TO_USER = 0x40000000;
// Flags used for indicating whether the internal and/or external input devices
@@ -744,11 +743,10 @@
* because it's the most fragile.
* @param event The key event.
* @param policyFlags The policy flags associated with the key.
- * @param isScreenOn True if the screen is already on
*
* @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
/**
* Called from the input reader thread before a motion is enqueued when the screen is off.
@@ -761,7 +759,7 @@
*
* @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 4dd8dcb..5b9372d 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -163,6 +163,19 @@
}
/**
+ * Gets the root {@link AccessibilityNodeInfo} in a given window.
+ *
+ * @param connectionId The id of a connection for interacting with the system.
+ * @param windowId The window id.
+ * @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
+ */
+ public AccessibilityNodeInfo getRootInWindow(int connectionId, int windowId) {
+ return findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId,
+ AccessibilityNodeInfo.ROOT_NODE_ID, false,
+ AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+ }
+
+ /**
* Gets the info for a window.
*
* @param connectionId The id of a connection for interacting with the system.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a6904f7..9d10930 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -77,6 +77,9 @@
public static final int ACTIVE_WINDOW_ID = UNDEFINED_ITEM_ID;
/** @hide */
+ public static final int ANY_WINDOW_ID = -2;
+
+ /** @hide */
public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
/** @hide */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 81d36a4..85168fd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1691,6 +1691,9 @@
* thread of this WebView. Care is therefore required to maintain thread
* safety.</li>
* <li> The Java object's fields are not accessible.</li>
+ * <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#L}
+ * and above, methods of injected Java objects are enumerable from
+ * JavaScript.</li>
* </ul>
*
* @param object the Java object to inject into this WebView's JavaScript
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 00b2c13..d6fa05a 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1991,7 +1991,16 @@
, '\u0669',
// Extended Arabic-Indic
'\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8'
- , '\u06f9'
+ , '\u06f9',
+ // Hindi and Marathi (Devanagari script)
+ '\u0966', '\u0967', '\u0968', '\u0969', '\u096a', '\u096b', '\u096c', '\u096d', '\u096e'
+ , '\u096f',
+ // Bengali
+ '\u09e6', '\u09e7', '\u09e8', '\u09e9', '\u09ea', '\u09eb', '\u09ec', '\u09ed', '\u09ee'
+ , '\u09ef',
+ // Kannada
+ '\u0ce6', '\u0ce7', '\u0ce8', '\u0ce9', '\u0cea', '\u0ceb', '\u0cec', '\u0ced', '\u0cee'
+ , '\u0cef'
};
/**
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 24e0b0a..7a4728d 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -49,6 +49,8 @@
jfieldID minDelay;
jfieldID fifoReservedEventCount;
jfieldID fifoMaxEventCount;
+ jfieldID stringType;
+ jfieldID requiredPermission;
} gSensorOffsets;
@@ -73,6 +75,9 @@
sensorOffsets.fifoReservedEventCount =
_env->GetFieldID(sensorClass, "mFifoReservedEventCount", "I");
sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount", "I");
+ sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
+ sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
+ "Ljava/lang/String;");
}
static jint
@@ -89,6 +94,8 @@
const SensorOffsets& sensorOffsets(gSensorOffsets);
jstring name = env->NewStringUTF(list->getName().string());
jstring vendor = env->NewStringUTF(list->getVendor().string());
+ jstring stringType = env->NewStringUTF(list->getStringType().string());
+ jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
env->SetObjectField(sensor, sensorOffsets.name, name);
env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
env->SetIntField(sensor, sensorOffsets.version, list->getVersion());
@@ -100,7 +107,11 @@
env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay());
env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
list->getFifoReservedEventCount());
- env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount());
+ env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
+ list->getFifoMaxEventCount());
+ env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+ env->SetObjectField(sensor, sensorOffsets.requiredPermission,
+ requiredPermission);
next++;
return size_t(next) < count ? next : 0;
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 31a1de6..8dacfeb 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -376,7 +376,8 @@
static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env,
jobject clazz, jlong renderNodePtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- return renderNode->stagingProperties().getMatrixFlags() == 0;
+ renderNode->mutateStagingProperties().updateMatrix();
+ return !renderNode->stagingProperties().hasTransformMatrix();
}
// ----------------------------------------------------------------------------
@@ -391,10 +392,7 @@
renderNode->mutateStagingProperties().updateMatrix();
const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix();
- if (renderNode->stagingProperties().getMatrixFlags() == TRANSLATION) {
- outMatrix->setTranslate(renderNode->stagingProperties().getTranslationX(),
- renderNode->stagingProperties().getTranslationY());
- } else if (transformMatrix) {
+ if (transformMatrix) {
*outMatrix = *transformMatrix;
} else {
outMatrix->setIdentity();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a83942f..b2709af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -483,6 +483,13 @@
android:label="@string/permlab_writeProfile"
android:description="@string/permdesc_writeProfile" />
+ <!-- Allows an application to access data from sensors that the user uses to
+ measure what is happening inside his/her body, such as heart rate. -->
+ <permission android:name="android.permission.BODY_SENSORS"
+ android:permissionGroup="android.permission-group.PERSONAL_INFO"
+ android:label="@string/permlab_bodySensors"
+ android:description="@string/permdesc_bodySensors" />
+
<!-- =============================================================== -->
<!-- Permissions for accessing the device calendar -->
<!-- =============================================================== -->
diff --git a/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..32ddf7a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..db9e172
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..805cb29
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..c3791fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrubber_control_selector_quantum.xml b/core/res/res/drawable/scrubber_control_selector_quantum.xml
index e31c2c1..e34f64a 100644
--- a/core/res/res/drawable/scrubber_control_selector_quantum.xml
+++ b/core/res/res/drawable/scrubber_control_selector_quantum.xml
@@ -15,12 +15,16 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="true" android:state_pressed="true">
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:state_pressed="true">
<bitmap android:src="@drawable/scrubber_control_on_pressed_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
<bitmap android:src="@drawable/scrubber_control_on_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
+ android:tint="?attr/colorControlActivated" />
</item>
</selector>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
index 7b124ac..d172b05 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
@@ -15,12 +15,24 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true">
- <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
</item>
<item>
- <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
+ <layer-list>
+ <item android:id="@id/background">
+ <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:id="@id/secondaryProgress">
+ <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:id="@id/progress">
+ <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ </layer-list>
</item>
</selector>
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
index c16a12c..1cf7ca9 100644
--- a/core/res/res/layout/volume_adjust.xml
+++ b/core/res/res/layout/volume_adjust.xml
@@ -15,23 +15,20 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="480dp"
+ android:layout_width="448dp"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/visible_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@android:drawable/dialog_full_holo_dark"
- android:orientation="horizontal"
- >
+ android:orientation="horizontal">
<LinearLayout
android:id="@+id/slider_group"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:orientation="vertical"
- >
+ android:orientation="vertical">
<!-- Sliders go here -->
</LinearLayout>
@@ -43,8 +40,7 @@
android:scaleType="fitXY"
android:layout_gravity="top"
android:layout_marginTop="16dip"
- android:layout_marginBottom="16dip"
- />
+ android:layout_marginBottom="16dip" />
<ImageView
android:id="@+id/expand_button"
@@ -53,8 +49,7 @@
android:layout_gravity="top"
android:padding="16dip"
android:background="?attr/selectableItemBackground"
- android:src="@drawable/ic_sysbar_quicksettings"
- />
+ android:src="@drawable/ic_sysbar_quicksettings" />
</LinearLayout>
</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/volume_adjust_item.xml b/core/res/res/layout/volume_adjust_item.xml
index 4a0fbaf..746cf91 100644
--- a/core/res/res/layout/volume_adjust_item.xml
+++ b/core/res/res/layout/volume_adjust_item.xml
@@ -26,16 +26,15 @@
android:id="@+id/stream_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="16dip"
+ android:paddingLeft="16dip"
android:background="?attr/selectableItemBackground"
- />
+ android:contentDescription="@null" />
<SeekBar
style="?android:attr/seekBarStyle"
android:id="@+id/seekbar"
- android:layout_width="300dp"
+ android:layout_width="252dp"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:padding="16dip"
android:layout_marginEnd="16dip" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 94123a2..6b2c788 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -201,7 +201,7 @@
<dimen name="textview_error_popup_default_width">240dip</dimen>
<!-- Volume panel y offset -->
- <dimen name="volume_panel_top">80dp</dimen>
+ <dimen name="volume_panel_top">16dp</dimen>
<!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. -->
<dimen name="default_app_widget_padding_left">8dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6266393..fde5e3f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1343,6 +1343,14 @@
as your name and contact information. This means the app can identify you
and may send your profile information to others.</string>
+ <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=30] -->
+ <string name="permlab_bodySensors">body sensors (like heart rate monitors)
+ </string>
+ <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_bodySensors" product="default">Allows the app to
+ access data from sensors you use to measure what’s happening inside your
+ body, such as heart rate.</string>
+
<!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] -->
<string name="permlab_readSocialStream" product="default">read your social stream</string>
<string name="permdesc_readSocialStream" product="default">Allows the app
diff --git a/docs/html/images/tools/as-android.png b/docs/html/images/tools/as-android.png
new file mode 100644
index 0000000..7808ed1
--- /dev/null
+++ b/docs/html/images/tools/as-android.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointline.png b/docs/html/images/tools/as-breakpointline.png
new file mode 100644
index 0000000..9aea880
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointline.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointswindow.png b/docs/html/images/tools/as-breakpointswindow.png
new file mode 100644
index 0000000..a40b459
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointswindow.png
Binary files differ
diff --git a/docs/html/images/tools/as-capture.png b/docs/html/images/tools/as-capture.png
new file mode 100644
index 0000000..02f9f6f
--- /dev/null
+++ b/docs/html/images/tools/as-capture.png
Binary files differ
diff --git a/docs/html/images/tools/as-currentproc.png b/docs/html/images/tools/as-currentproc.png
new file mode 100644
index 0000000..4be8305
--- /dev/null
+++ b/docs/html/images/tools/as-currentproc.png
Binary files differ
diff --git a/docs/html/images/tools/as-ddmslog.png b/docs/html/images/tools/as-ddmslog.png
new file mode 100644
index 0000000..b53b8fe
--- /dev/null
+++ b/docs/html/images/tools/as-ddmslog.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugbutton.png b/docs/html/images/tools/as-debugbutton.png
new file mode 100644
index 0000000..55e95d1
--- /dev/null
+++ b/docs/html/images/tools/as-debugbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugdevices.png b/docs/html/images/tools/as-debugdevices.png
new file mode 100644
index 0000000..09a9d0e
--- /dev/null
+++ b/docs/html/images/tools/as-debugdevices.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugview.png b/docs/html/images/tools/as-debugview.png
new file mode 100644
index 0000000..0349147
--- /dev/null
+++ b/docs/html/images/tools/as-debugview.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugwindowbutton.png b/docs/html/images/tools/as-debugwindowbutton.png
new file mode 100644
index 0000000..9016778
--- /dev/null
+++ b/docs/html/images/tools/as-debugwindowbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-devicecapture.png b/docs/html/images/tools/as-devicecapture.png
new file mode 100644
index 0000000..3236a89
--- /dev/null
+++ b/docs/html/images/tools/as-devicecapture.png
Binary files differ
diff --git a/docs/html/images/tools/as-evalexpbutton.png b/docs/html/images/tools/as-evalexpbutton.png
new file mode 100644
index 0000000..85b3c74
--- /dev/null
+++ b/docs/html/images/tools/as-evalexpbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-launchavdm.png b/docs/html/images/tools/as-launchavdm.png
new file mode 100644
index 0000000..bf15981
--- /dev/null
+++ b/docs/html/images/tools/as-launchavdm.png
Binary files differ
diff --git a/docs/html/images/tools/as-monitorbutton.png b/docs/html/images/tools/as-monitorbutton.png
new file mode 100644
index 0000000..6bdc3a5
--- /dev/null
+++ b/docs/html/images/tools/as-monitorbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-record.png b/docs/html/images/tools/as-record.png
new file mode 100644
index 0000000..5f7fa99
--- /dev/null
+++ b/docs/html/images/tools/as-record.png
Binary files differ
diff --git a/docs/html/images/tools/as-restart.png b/docs/html/images/tools/as-restart.png
new file mode 100644
index 0000000..12d2923
--- /dev/null
+++ b/docs/html/images/tools/as-restart.png
Binary files differ
diff --git a/docs/html/images/tools/as-resumeprogrambutton.png b/docs/html/images/tools/as-resumeprogrambutton.png
new file mode 100644
index 0000000..8096937
--- /dev/null
+++ b/docs/html/images/tools/as-resumeprogrambutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-showdevview.png b/docs/html/images/tools/as-showdevview.png
new file mode 100644
index 0000000..602a6ad
--- /dev/null
+++ b/docs/html/images/tools/as-showdevview.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepintobutton.png b/docs/html/images/tools/as-stepintobutton.png
new file mode 100644
index 0000000..569d4ed
--- /dev/null
+++ b/docs/html/images/tools/as-stepintobutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoutbutton.png b/docs/html/images/tools/as-stepoutbutton.png
new file mode 100644
index 0000000..ef8871f
--- /dev/null
+++ b/docs/html/images/tools/as-stepoutbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoverbutton.png b/docs/html/images/tools/as-stepoverbutton.png
new file mode 100644
index 0000000..1c487df
--- /dev/null
+++ b/docs/html/images/tools/as-stepoverbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-variablesview.png b/docs/html/images/tools/as-variablesview.png
new file mode 100644
index 0000000..6a0b987
--- /dev/null
+++ b/docs/html/images/tools/as-variablesview.png
Binary files differ
diff --git a/docs/html/images/tools/as-varviewbutton.png b/docs/html/images/tools/as-varviewbutton.png
new file mode 100644
index 0000000..2ad4c58
--- /dev/null
+++ b/docs/html/images/tools/as-varviewbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-viewbreakbutton.png b/docs/html/images/tools/as-viewbreakbutton.png
new file mode 100644
index 0000000..22723d4
--- /dev/null
+++ b/docs/html/images/tools/as-viewbreakbutton.png
Binary files differ
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 9d5e8c1..6b63ba7 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -35,10 +35,10 @@
</div>
-
+
<div id="mac" class="docs" style="display:none">
-
+
<h3>Getting started on Mac</h3>
<ol>
@@ -62,7 +62,7 @@
<div id="linux" class="docs" style="display:none">
-
+
<h3>Getting started on Linux</h3>
<ol>
@@ -97,17 +97,23 @@
<li>Here are the steps to install Java and Eclipse, prior to installing
the Android SDK and ADT Plugin.
<ol>
- <li>If you are running a 64-bit distribution on your development
- machine, you need to install the <code>ia32-libs</code> package using
- <code>apt-get:</code>:
- <pre>apt-get install ia32-libs</pre>
+ <li><p>If you are running a 64-bit distribution on your development
+ machine, you need to install additional packages first. For Ubuntu 13.10 (Saucy Salamander)
+ and above, install the <code>libncurses5:i386</code>, <code>libstdc++6:i386</code>, and
+ <code>zlib1g:i386</code> packages using <code>apt-get</code>:</p>
+ <pre class="no-pretty-print">sudo dpkg --add-architecture i386
+sudo apt-get update
+sudo apt-get install libncurses5:i386 libstdc++6:i386 zlib1g:i386</pre>
+ <p>For earlier versions of Ubuntu, install the <code>ia32-libs</code> package using
+ <code>apt-get</code>:</p>
+ <pre class="no-pretty-print">apt-get install ia32-libs</pre>
</li>
- <li>Next, install Java: <pre>apt-get install sun-java6-jdk</pre></li>
- <li>The Ubuntu package manager does not currently offer an Eclipse 3.6
+ <li>Next, install Java: <pre class="no-pretty-print">apt-get install sun-java6-jdk</pre></li>
+ <li>The Ubuntu package manager does not currently offer an Eclipse 3.7
version for download, so we recommend that you download Eclipse from
eclipse.org (<a
- href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
- downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
+ href="http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>).
+ A Java or RCP version of Eclipse is recommended.</li>
<li>Follow the steps given in previous sections to install the SDK
and the ADT plugin. </li>
</ol>
@@ -137,7 +143,7 @@
// not running a compatible OS, so just show all the docs
$('.docs').show();
}
-
+
function showAll() {
$('.docs').each(function() {
if (!$(this).is(':visible')) {
diff --git a/docs/html/sdk/installing/studio-debug.jd b/docs/html/sdk/installing/studio-debug.jd
new file mode 100644
index 0000000..7e2efe3
--- /dev/null
+++ b/docs/html/sdk/installing/studio-debug.jd
@@ -0,0 +1,346 @@
+page.title=Debugging with Android Studio
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#runDebug">Run your App in Debug Mode</a></li>
+ <li><a href="#systemLog">Use the System Log</a>
+ <ol>
+ <li><a href="#systemLogWrite">Write log messages in your code</a></li>
+ <li><a href="#systemLogView">View the system log</a></li>
+ </ol>
+ </li>
+ <li><a href="#breakPoints">Work with Breakpoints</a>
+ <ol>
+ <li><a href="#breakPointsView">View and configure breakpoints</a></li>
+ <li><a href="#breakPointsDebug">Debug your app with breakpoints</a></li>
+ </ol>
+ </li>
+ <li><a href="#deviceMonitor">Analyze Runtime Metrics to Optimize your App</a></li>
+ <li><a href="#screenCap">Capture Screenshots and Videos</a></li>
+</ol>
+<h2>See also</h2>
+<ul>
+<li><a href="{@docRoot}sdk/installing/studio-tips.html">
+Android Studio Tips and Tricks</a></li>
+<li><a href="{@docRoot}tools/debugging/index.html">Debugging</a></li>
+<li><a href="{@docRoot}tools/help/monitor.html">Device Monitor</a></li>
+<li><a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a></li>
+</div>
+</div>
+
+<p>Android Studio enables you to debug apps running on the emulator or on an Android device.
+With Android Studio, you can:</p>
+
+<ul>
+ <li>Select a device to debug your app on.</li>
+ <li>View the system log.</li>
+ <li>Set breakpoints in your code.</li>
+ <li>Examine variables and evaluate expressions at run time.</li>
+ <li>Run the debugging tools from the Android SDK.</li>
+ <li>Capture screenshots and videos of your app.</li>
+</ul>
+
+<p>To debug your app, Android Studio builds a debuggable version of your app, connects
+to a device or to the emulator, installs the app and runs it. The IDE shows the system log
+while your app is running and provides debugging tools to filter log messages, work with
+breakpoints, and control the execution flow.</p>
+
+
+<h2 id="runDebug">Run your App in Debug Mode</h2>
+
+<div class="figure" style="width:419px">
+ <img src="{@docRoot}images/tools/as-debugdevices.png" alt=""/>
+ <p class="img-caption"><strong>Figure 1.</strong> The Choose Device window enables you to
+ select a physical Android device or a virtual device to debug your app.</p>
+</div>
+
+<p>To run your app in debug mode, you build an APK signed with a debug key and install it on a
+physical Android device or on the Android emulator.
+To set up an Android device for development, see <a href="{@docRoot}tools/device.html">Using
+Hardware Devices</a>. For more information about the emulator provided by the Android SDK, see
+<a href="{@docRoot}tools/devices/emulator.html">Using the Emulator.</a></p>
+
+<p>To debug your app in Android Studio:</p>
+
+<ol>
+ <li>Open your project in Android Studio.</li>
+ <li>Click <strong>Debug</strong> <img src="{@docRoot}images/tools/as-debugbutton.png"
+ style="vertical-align:bottom;margin:0;height:22px" alt=""/> in the toolbar.</li>
+ <li>On the <em>Choose Device</em> window, select a hardware device from the list or
+ choose a virtual device.</li>
+ <li>Click <strong>OK</strong>. Your app starts on the selected device.</li>
+</ol>
+
+<p>Figure 1 shows the <em>Choose Device</em> window. The list shows all the Android devices
+connected to your computer. Select <strong>Launch Emulator</strong> to use an Android virtual device
+instead. Click the ellipsis <img src="{@docRoot}images/tools/as-launchavdm.png"
+style="vertical-align:bottom;margin:0;height:19px" alt=""/> to open the
+<a href="{@docRoot}tools/devices/managing-avds.html">Android Virtual Device Manager</a>.</p>
+
+<p>Android Studio opens the <em>Debug</em> tool window when you debug your app. To open the
+<em>Debug</em> window manually, click <strong>Debug</strong>
+<img src="{@docRoot}images/tools/as-debugwindowbutton.png"
+alt="" style="vertical-align:bottom;margin:0;height:20px"/>.
+This window shows threads and variables in the <em>Debugger</em> tab, the device status in the
+<em>Console</em> tab, and the system log in the <em>Logcat</em> tab. The <em>Debug</em> tool
+window also provides other debugging tools covered in the following sections.</p>
+
+<img src="{@docRoot}images/tools/as-debugview.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> The Debug tool window in Android Studio showing
+the current thread and the object tree for a variable.</p>
+
+
+<h2 id="systemLog">Use the System Log</h2>
+
+<p>The system log shows system messages while you debug your app. These messages include
+information from apps running on the device. If you want to use the
+system log to debug your app, make sure your code writes log messages and prints the stack
+trace for exceptions while your app is in the development phase.</p>
+
+<h3 id="systemLogWrite">Write log messages in your code</h3>
+
+<p>To write log messages in your code, use the {@link android.util.Log} class. Log messages
+help you understand the execution flow by collecting the system debug output while you interact
+with your app. Log messages can tell you what part of your application failed. For more
+information about logging, see <a href="{@docRoot}tools/debugging/debugging-log.html">
+Reading and Writing Logs</a>.</p>
+
+<p>The following example shows how you might add log messages to determine if previous state
+information is available when your activity starts:</p>
+
+<pre>
+import android.util.Log;
+...
+public class MyActivity extends Activity {
+ private static final String TAG = MyActivity.class.getSimpleName();
+ ...
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ if (savedInstanceState != null) {
+ Log.d(TAG, "onCreate() Restoring previous state");
+ /* restore state */
+ } else {
+ Log.d(TAG, "onCreate() No saved state available");
+ /* initialize app */
+ }
+ }
+}
+</pre>
+
+<p>During development, your code can also catch exceptions and write the stack trace to the system
+log:</p>
+
+<pre>
+void someOtherMethod() {
+ try {
+ ...
+ } catch (SomeException e) {
+ Log.d(TAG, "someOtherMethod()", e);
+ }
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> Remove debug log messages and stack trace print calls from
+your code when you are ready to publish your app. You could do this by setting a <code>DEBUG</code>
+flag and placing debug log messages inside conditional statements.</p>
+
+
+<h3 id="systemLogView">View the system log</h3>
+
+<p>Both the <em>Android DDMS</em> (Dalvik Debug Monitor Server) and the <em>Debug</em> tool windows
+show the system log; however, the <em>Android DDMS</em> tool window lets you view only log messages
+for a particular process. To view the system log on the <em>Android DDMS</em> tool window:</p>
+
+<ol>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+ <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+ tool window.</li>
+ <li>If the system log is empty in the <em>Logcat view</em>, click <strong>Restart</strong>
+ <img src="{@docRoot}images/tools/as-restart.png" alt=""
+ style="vertical-align:bottom;margin:0;height:22px"/>.</li>
+</ol>
+
+<img src="{@docRoot}images/tools/as-ddmslog.png" alt="" />
+<p class="img-caption"><strong>Figure 4.</strong> The system log in the Android DDMS tool
+window.</p>
+
+<p>The <em>Android DDMS</em> tool window gives you access to some DDMS features from Android Studio.
+For more information about DDMS, see <a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.
+</p>
+
+<p>The system log shows messages from Android services and other Android apps. To filter the log
+messages to view only the ones you are interested in, use the tools in the <em>Android DDMS</em>
+window:</p>
+
+<ul>
+ <li>To show only log messages for a particular process, select the process in the
+ <em>Devices</em> view and then click <strong>Only Show Logcat from Selected
+ Process</strong> <img src="{@docRoot}images/tools/as-currentproc.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>. If the <em>Devices</em> view
+ is not available, click <strong>Restore Devices View</strong>
+ <img src="{@docRoot}images/tools/as-showdevview.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> on the right of the <em>Android
+ DDMS</em> tool window. This button is only visible when you hide the <em>Devices</em>
+ window.</li>
+ <li>To filter log messages by log level, select a level under <em>Log Level</em> on the top
+ of the <em>Android DDMS</em> window.</li>
+ <li>To show only log messages that contain a particular string, enter the string in the search
+ box and press <strong>Enter</strong>.</li>
+</ul>
+
+
+<h2 id="breakPoints">Work with Breakpoints</h2>
+
+<p>Breakpoints enable you to pause the execution of your app at a particular line of code, examine
+variables, evaluate expressions, and continue the execution line by line. Use breakpoints to
+determine the causes of run-time errors that you can't fix by looking at your code only. To debug
+your app using breakpoints:</p>
+
+<ol>
+ <li>Open the source file in which you want to set a breakpoint.</li>
+ <li>Locate the line where you want to set a breakpoint and click on it.</li>
+ <li>Click on the yellow portion of the side bar to the left of this line, as shown in figure 5.</li>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+</ol>
+
+<p>Android Studio pauses the execution of your app when it reaches the breakpoint. You can then
+use the tools in the <em>Debug</em> tool window to identify the cause of the error.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointline.png" alt="" />
+<p class="img-caption"><strong>Figure 5.</strong> A red dot appears next to the line when you set
+a breakpoint.</p>
+
+<h3 id="breakPointsView">View and configure breakpoints</h3>
+
+<p>To view all the breakpoints and configure breakpoint settings, click <strong>View
+Breakpoints</strong> <img src="{@docRoot}images/tools/as-viewbreakbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the left side of the <em>Debug</em> tool
+window. The <em>Breakpoints</em> window appears, as shown in figure 6.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointswindow.png" alt="" />
+<p class="img-caption"><strong>Figure 6.</strong> The Breakpoints window lists all the current
+breakpoints and includes behavior settings for each.</p>
+
+<p>The <em>Breakpoints</em> window lets you enable or disable each breakpoint from the
+list on the left. If a breakpoint is disabled, Android Studio does not pause your app when
+it hits that breakpoint. Select a breakpoint from the list to configure its settings.
+You can configure a breakpoint to be disabled at first and have the system enable it after a
+different breakpoint is hit. You can also configure whether a breakpoint should be disabled after
+it is hit. To set a breakpoint for any exception, select <strong>Exception Breakpoints</strong>
+in the list of breakpoints.</p>
+
+<h3 id="breakPointsDebug">Debug your app with breakpoints</h3>
+
+<p>After you set breakpoints in your code, click <strong>Rerun</strong>
+<img src="{@docRoot}images/tools/as-restart.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> to start the app again. When a breakpoint is
+hit, Android Studio pauses the app and highlights the breakpoint in the source code. The
+<em>Debug</em> tool window lets you examine variables and control the execution step by
+step:</p>
+
+<ul>
+ <li>
+ <p>To examine the object tree for a variable, expand it in the <em>Variables</em> view. If
+ the <em>Variables</em> view is not visible, click <strong>Restore Variables View</strong>
+ <img src="{@docRoot}images/tools/as-varviewbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To evaluate an expression at the current execution point, click <strong>Evaluate
+ Expression</strong> <img src="{@docRoot}images/tools/as-evalexpbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To advance to the next line in the code (without entering a method), click <strong>Step
+ Over</strong> <img src="{@docRoot}images/tools/as-stepoverbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To advance to the first line inside a method call, click <strong>Step
+ Into</strong> <img src="{@docRoot}images/tools/as-stepintobutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To advance to the next line outside the current method, click <strong>Step
+ Out</strong> <img src="{@docRoot}images/tools/as-stepoutbutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+ <li>
+ <p>To continue running the app normally, click <strong>Resume Program</strong>
+ <img src="{@docRoot}images/tools/as-resumeprogrambutton.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+ </li>
+</ul>
+
+<img src="{@docRoot}images/tools/as-variablesview.png" alt="" />
+<p class="img-caption"><strong>Figure 7.</strong> The Variables view in the Debug tool window.</p>
+
+
+<h2 id="deviceMonitor">Analyze Runtime Metrics to Optimize your App</h2>
+
+<p>Even if your application does not generate runtime errors, this does not mean it is free of
+problems. You should also consider the following issues:</p>
+
+<ul>
+ <li>Does your app use memory efficiently?</li>
+ <li>Does your app generate unnecessary network traffic?</li>
+ <li>What methods should you focus your attention on to improve the performance of your app?</li>
+ <li>Does your app behave properly when the user receives a phone call or a message?</li>
+</ul>
+
+<p>The Android Device Monitor is a stand-alone tool with a graphical user interface for serveral
+Android application debugging and analysis tools, including the Dalvik Debug Monitor Server (DDMS).
+You can use the Android Device Monitor to analyze memory usage, profile methods,
+monitor network traffic and simulate incoming calls and messages.</p>
+
+<p>To open the Android Device Monitor from Android Studio, click
+<strong>Monitor</strong> <img src="{@docRoot}images/tools/as-monitorbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the toolbar. The Android Device Monitor
+opens in a new window.</p>
+
+<p>For more information about the Android Device Monitor and DDMS, see
+<a href="{@docRoot}tools/help/monitor.html">Device Monitor</a> and
+<a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.</p>
+
+
+<h2 id="screenCap">Capture Screenshots and Videos</h2>
+
+<p>Android Studio enables you to capture a screenshot or a short video of the device screen
+while your app is running. Screenshots and videos are useful as promotional materials for your
+app, and you can also attach them to bug reports that you send to your development team.</p>
+
+<p>To take a screenshot of your app:</p>
+
+<ol>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+ <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+ tool window.</li>
+ <li>Click <strong>Screen Capture</strong> <img src="{@docRoot}images/tools/as-capture.png"
+ style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+ <em>Android DDMS</em> tool window.</li>
+ <li>Optional: To add a device frame around your screenshot, enable the <em>Frame screenshot</em>
+ option.</li>
+ <li>Click <strong>Save</strong>.</li>
+</ol>
+
+<p>To take a video recording of your app:</p>
+
+<ol>
+ <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+ <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+ style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+ tool window.</li>
+ <li>Click <strong>Screen Record</strong> <img src="{@docRoot}images/tools/as-record.png"
+ style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+ <em>Android DDMS</em> tool window.</li>
+ <li>Click <strong>Start Recording</strong>.</li>
+ <li>Interact with your app.</li>
+ <li>Click <strong>Stop Recording</strong>.</li>
+ <li>Enter a file name for the recording and click <strong>OK</strong>.</li>
+</ol>
\ No newline at end of file
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index c281644..b29b87c 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -38,6 +38,8 @@
Using the Layout Editor</a></li>
<li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
Building Your Project with Gradle</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
+ Debugging with Android Studio</a></li>
</ul>
</li>
<li><a href="<?cs var:toroot ?>sdk/exploring.html">
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 2810c43..3773a49 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -44,9 +44,6 @@
* Documentation pending.
*/
public class TouchFeedbackDrawable extends LayerDrawable {
- private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
- private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
-
/** The maximum number of ripples supported. */
private static final int MAX_RIPPLES = 10;
@@ -153,10 +150,8 @@
* @param tintMode A Porter-Duff blending mode
*/
public void setTintMode(Mode tintMode) {
- if (mState.mTintMode != tintMode) {
- mState.mTintMode = tintMode;
- invalidateSelf();
- }
+ mState.setTintMode(tintMode);
+ invalidateSelf();
}
@Override
@@ -187,8 +182,8 @@
}
if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
- mState.mTintMode = Drawable.parseTintMode(
- a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+ mState.setTintMode(Drawable.parseTintMode(
+ a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
}
if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
@@ -238,8 +233,8 @@
}
if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
- mState.mTintMode = Drawable.parseTintMode(
- a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+ mState.setTintMode(Drawable.parseTintMode(
+ a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
}
if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
@@ -382,8 +377,9 @@
// If we have ripples and content, we need a masking layer. This will
// merge DST_ATOP onto (effectively under) the ripple layer.
if (drewRipples && !projected && rippleRestoreCount >= 0) {
+ final PorterDuffXfermode xfermode = mState.getTintXfermode();
canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, getMaskingPaint(DST_ATOP), 0);
+ bounds.right, bounds.bottom, getMaskingPaint(xfermode), 0);
}
Drawable mask = null;
@@ -401,7 +397,7 @@
if (mask != null && drewRipples) {
// TODO: This will also mask the lower layer, which is bad.
canvas.saveLayer(bounds.left, bounds.top, bounds.right,
- bounds.bottom, getMaskingPaint(DST_IN), 0);
+ bounds.bottom, getMaskingPaint(mState.mTintXfermode), 0);
mask.draw(canvas);
}
@@ -459,7 +455,7 @@
static class TouchFeedbackState extends LayerState {
int[] mTouchThemeAttrs;
ColorStateList mTint;
- Mode mTintMode;
+ PorterDuffXfermode mTintXfermode;
boolean mPinned;
public TouchFeedbackState(
@@ -469,10 +465,19 @@
if (orig != null) {
mTouchThemeAttrs = orig.mTouchThemeAttrs;
mTint = orig.mTint;
- mTintMode = orig.mTintMode;
+ mTintXfermode = orig.mTintXfermode;
mPinned = orig.mPinned;
}
}
+
+ public void setTintMode(Mode mode) {
+ final Mode invertedMode = TouchFeedbackState.invertPorterDuffMode(mode);
+ mTintXfermode = new PorterDuffXfermode(invertedMode);
+ }
+
+ public PorterDuffXfermode getTintXfermode() {
+ return mTintXfermode;
+ }
@Override
public boolean canApplyTheme() {
@@ -493,6 +498,33 @@
public Drawable newDrawable(Resources res, Theme theme) {
return new TouchFeedbackDrawable(this, res, theme);
}
+
+ /**
+ * Inverts SRC and DST in PorterDuff blending modes.
+ */
+ private static Mode invertPorterDuffMode(Mode src) {
+ switch (src) {
+ case SRC_ATOP:
+ return Mode.DST_ATOP;
+ case SRC_IN:
+ return Mode.DST_IN;
+ case SRC_OUT:
+ return Mode.DST_OUT;
+ case SRC_OVER:
+ return Mode.DST_OVER;
+ case DST_ATOP:
+ return Mode.SRC_ATOP;
+ case DST_IN:
+ return Mode.SRC_IN;
+ case DST_OUT:
+ return Mode.SRC_OUT;
+ case DST_OVER:
+ return Mode.SRC_OVER;
+ default:
+ // Everything else is agnostic to SRC versus DST.
+ return src;
+ }
+ }
}
private TouchFeedbackDrawable(TouchFeedbackState state, Resources res, Theme theme) {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 823ae7b..2489c92 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -154,8 +154,8 @@
} else if (properties().getAnimationMatrix()) {
renderer.concatMatrix(properties().getAnimationMatrix());
}
- if (properties().getMatrixFlags() != 0) {
- if (properties().getMatrixFlags() == TRANSLATION) {
+ if (properties().hasTransformMatrix()) {
+ if (properties().isTransformTranslateOnly()) {
renderer.translate(properties().getTranslationX(), properties().getTranslationY());
} else {
renderer.concatMatrix(*properties().getTransformMatrix());
@@ -214,8 +214,8 @@
mat4 anim(*properties().getAnimationMatrix());
matrix.multiply(anim);
}
- if (properties().getMatrixFlags() != 0) {
- if (properties().getMatrixFlags() == TRANSLATION) {
+ if (properties().hasTransformMatrix()) {
+ if (properties().isTransformTranslateOnly()) {
matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
true3dTransform ? properties().getTranslationZ() : 0.0f);
} else {
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index e7e7768..08829ef 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -27,6 +27,16 @@
#include "Matrix.h"
+/**
+ * Convenience value to check for float values that are close enough to zero to be considered
+ * zero.
+ */
+#define NONZERO_EPSILON .001f
+
+static inline bool is_zero(float value) {
+ return (value >= -NONZERO_EPSILON) || (value <= NONZERO_EPSILON);
+}
+
namespace android {
namespace uirenderer {
@@ -42,22 +52,18 @@
, mPivotX(0), mPivotY(0)
, mLeft(0), mTop(0), mRight(0), mBottom(0)
, mWidth(0), mHeight(0)
- , mPrevWidth(-1), mPrevHeight(-1)
, mPivotExplicitlySet(false)
- , mMatrixDirty(false)
- , mMatrixFlags(0)
+ , mMatrixOrPivotDirty(false)
, mCaching(false) {
}
RenderProperties::ComputedFields::ComputedFields()
: mTransformMatrix(NULL)
- , mTransformMatrix3D(NULL)
, mClipPath(NULL) {
}
RenderProperties::ComputedFields::~ComputedFields() {
delete mTransformMatrix;
- delete mTransformMatrix3D;
delete mClipPath;
}
@@ -82,7 +88,7 @@
updateClipPath();
// Force recalculation of the matrix, since other's dirty bit may be clear
- mPrimitiveFields.mMatrixDirty = true;
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
updateMatrix();
}
return *this;
@@ -100,8 +106,8 @@
ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
}
- if (mPrimitiveFields.mMatrixFlags != 0) {
- if (mPrimitiveFields.mMatrixFlags == TRANSLATION) {
+ if (hasTransformMatrix()) {
+ if (isTransformTranslateOnly()) {
ALOGD("%*sTranslate %.2f, %.2f, %.2f",
level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
} else {
@@ -134,52 +140,36 @@
}
void RenderProperties::updateMatrix() {
- if (mPrimitiveFields.mMatrixDirty) {
- // NOTE: mComputedFields.mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
- // to a pure translate. This is safe because the mPrimitiveFields.matrix isn't read in pure translate cases.
- if (mPrimitiveFields.mMatrixFlags && mPrimitiveFields.mMatrixFlags != TRANSLATION) {
- if (!mComputedFields.mTransformMatrix) {
- // only allocate a mPrimitiveFields.matrix if we have a complex transform
- mComputedFields.mTransformMatrix = new SkMatrix();
- }
- if (!mPrimitiveFields.mPivotExplicitlySet) {
- if (mPrimitiveFields.mWidth != mPrimitiveFields.mPrevWidth || mPrimitiveFields.mHeight != mPrimitiveFields.mPrevHeight) {
- mPrimitiveFields.mPrevWidth = mPrimitiveFields.mWidth;
- mPrimitiveFields.mPrevHeight = mPrimitiveFields.mHeight;
- mPrimitiveFields.mPivotX = mPrimitiveFields.mPrevWidth / 2.0f;
- mPrimitiveFields.mPivotY = mPrimitiveFields.mPrevHeight / 2.0f;
- }
- }
-
- if ((mPrimitiveFields.mMatrixFlags & ROTATION_3D) == 0) {
- mComputedFields.mTransformMatrix->setTranslate(
- mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY);
- mComputedFields.mTransformMatrix->preRotate(mPrimitiveFields.mRotation,
- mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
- mComputedFields.mTransformMatrix->preScale(
- mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
- mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
- } else {
- if (!mComputedFields.mTransformMatrix3D) {
- mComputedFields.mTransformMatrix3D = new SkMatrix();
- }
- mComputedFields.mTransformMatrix->reset();
- mComputedFields.mTransformCamera.save();
- mComputedFields.mTransformMatrix->preScale(
- mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
- mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
- mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
- mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
- mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
- mComputedFields.mTransformCamera.getMatrix(mComputedFields.mTransformMatrix3D);
- mComputedFields.mTransformMatrix3D->preTranslate(-mPrimitiveFields.mPivotX, -mPrimitiveFields.mPivotY);
- mComputedFields.mTransformMatrix3D->postTranslate(mPrimitiveFields.mPivotX + mPrimitiveFields.mTranslationX,
- mPrimitiveFields.mPivotY + mPrimitiveFields.mTranslationY);
- mComputedFields.mTransformMatrix->postConcat(*mComputedFields.mTransformMatrix3D);
- mComputedFields.mTransformCamera.restore();
- }
+ if (mPrimitiveFields.mMatrixOrPivotDirty) {
+ if (!mComputedFields.mTransformMatrix) {
+ // only allocate a mPrimitiveFields.matrix if we have a complex transform
+ mComputedFields.mTransformMatrix = new SkMatrix();
}
- mPrimitiveFields.mMatrixDirty = false;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f;
+ mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f;
+ }
+ SkMatrix* transform = mComputedFields.mTransformMatrix;
+ transform->reset();
+ if (is_zero(getRotationX()) && is_zero(getRotationY())) {
+ transform->setTranslate(getTranslationX(), getTranslationY());
+ transform->preRotate(getRotation(), getPivotX(), getPivotY());
+ transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+ } else {
+ SkMatrix transform3D;
+ mComputedFields.mTransformCamera.save();
+ transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+ mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
+ mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
+ mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
+ mComputedFields.mTransformCamera.getMatrix(&transform3D);
+ transform3D.preTranslate(-getPivotX(), -getPivotY());
+ transform3D.postTranslate(getPivotX() + getTranslationX(),
+ getPivotY() + getTranslationY());
+ transform->postConcat(transform3D);
+ mComputedFields.mTransformCamera.restore();
+ }
+ mPrimitiveFields.mMatrixOrPivotDirty = false;
}
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index dd68210..4270da2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -28,12 +28,6 @@
#include "RevealClip.h"
#include "Outline.h"
-#define TRANSLATION 0x0001
-#define ROTATION 0x0002
-#define ROTATION_3D 0x0004
-#define SCALE 0x0008
-#define PIVOT 0x0010
-
class SkBitmap;
class SkPaint;
@@ -114,7 +108,7 @@
void setTranslationX(float translationX) {
if (translationX != mPrimitiveFields.mTranslationX) {
mPrimitiveFields.mTranslationX = translationX;
- onTranslationUpdate();
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -125,7 +119,7 @@
void setTranslationY(float translationY) {
if (translationY != mPrimitiveFields.mTranslationY) {
mPrimitiveFields.mTranslationY = translationY;
- onTranslationUpdate();
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -136,7 +130,7 @@
void setTranslationZ(float translationZ) {
if (translationZ != mPrimitiveFields.mTranslationZ) {
mPrimitiveFields.mTranslationZ = translationZ;
- onTranslationUpdate();
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -147,12 +141,7 @@
void setRotation(float rotation) {
if (rotation != mPrimitiveFields.mRotation) {
mPrimitiveFields.mRotation = rotation;
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mRotation == 0.0f) {
- mPrimitiveFields.mMatrixFlags &= ~ROTATION;
- } else {
- mPrimitiveFields.mMatrixFlags |= ROTATION;
- }
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -163,12 +152,7 @@
void setRotationX(float rotationX) {
if (rotationX != mPrimitiveFields.mRotationX) {
mPrimitiveFields.mRotationX = rotationX;
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
- mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
- } else {
- mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
- }
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -179,12 +163,7 @@
void setRotationY(float rotationY) {
if (rotationY != mPrimitiveFields.mRotationY) {
mPrimitiveFields.mRotationY = rotationY;
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
- mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
- } else {
- mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
- }
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -195,12 +174,7 @@
void setScaleX(float scaleX) {
if (scaleX != mPrimitiveFields.mScaleX) {
mPrimitiveFields.mScaleX = scaleX;
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
- mPrimitiveFields.mMatrixFlags &= ~SCALE;
- } else {
- mPrimitiveFields.mMatrixFlags |= SCALE;
- }
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -211,12 +185,7 @@
void setScaleY(float scaleY) {
if (scaleY != mPrimitiveFields.mScaleY) {
mPrimitiveFields.mScaleY = scaleY;
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
- mPrimitiveFields.mMatrixFlags &= ~SCALE;
- } else {
- mPrimitiveFields.mMatrixFlags |= SCALE;
- }
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
@@ -226,12 +195,7 @@
void setPivotX(float pivotX) {
mPrimitiveFields.mPivotX = pivotX;
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
- mPrimitiveFields.mMatrixFlags &= ~PIVOT;
- } else {
- mPrimitiveFields.mMatrixFlags |= PIVOT;
- }
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
mPrimitiveFields.mPivotExplicitlySet = true;
}
@@ -245,12 +209,7 @@
void setPivotY(float pivotY) {
mPrimitiveFields.mPivotY = pivotY;
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
- mPrimitiveFields.mMatrixFlags &= ~PIVOT;
- } else {
- mPrimitiveFields.mMatrixFlags |= PIVOT;
- }
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
mPrimitiveFields.mPivotExplicitlySet = true;
}
@@ -264,7 +223,7 @@
void setCameraDistance(float distance) {
if (distance != getCameraDistance()) {
- mPrimitiveFields.mMatrixDirty = true;
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
}
}
@@ -278,8 +237,8 @@
if (left != mPrimitiveFields.mLeft) {
mPrimitiveFields.mLeft = left;
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -292,8 +251,8 @@
if (top != mPrimitiveFields.mTop) {
mPrimitiveFields.mTop = top;
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -306,8 +265,8 @@
if (right != mPrimitiveFields.mRight) {
mPrimitiveFields.mRight = right;
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -320,8 +279,8 @@
if (bottom != mPrimitiveFields.mBottom) {
mPrimitiveFields.mBottom = bottom;
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -336,8 +295,8 @@
mPrimitiveFields.mTop = top;
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -350,8 +309,8 @@
mPrimitiveFields.mBottom = bottom;
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -360,8 +319,8 @@
if (offset != 0) {
mPrimitiveFields.mLeft += offset;
mPrimitiveFields.mRight += offset;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -370,8 +329,8 @@
if (offset != 0) {
mPrimitiveFields.mTop += offset;
mPrimitiveFields.mBottom += offset;
- if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixDirty = true;
+ if (!mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
}
}
}
@@ -392,11 +351,17 @@
return mAnimationMatrix;
}
- uint32_t getMatrixFlags() const {
- return mPrimitiveFields.mMatrixFlags;
+ bool hasTransformMatrix() const {
+ return getTransformMatrix() && !getTransformMatrix()->isIdentity();
+ }
+
+ // May only call this if hasTransformMatrix() is true
+ bool isTransformTranslateOnly() const {
+ return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask;
}
const SkMatrix* getTransformMatrix() const {
+ LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!");
return mComputedFields.mTransformMatrix;
}
@@ -452,14 +417,6 @@
}
private:
- void onTranslationUpdate() {
- mPrimitiveFields.mMatrixDirty = true;
- if (mPrimitiveFields.mTranslationX == 0.0f && mPrimitiveFields.mTranslationY == 0.0f && mPrimitiveFields.mTranslationZ == 0.0f) {
- mPrimitiveFields.mMatrixFlags &= ~TRANSLATION;
- } else {
- mPrimitiveFields.mMatrixFlags |= TRANSLATION;
- }
- }
// Rendering properties
struct PrimitiveFields {
@@ -478,10 +435,8 @@
float mPivotX, mPivotY;
int mLeft, mTop, mRight, mBottom;
int mWidth, mHeight;
- int mPrevWidth, mPrevHeight;
bool mPivotExplicitlySet;
- bool mMatrixDirty;
- uint32_t mMatrixFlags;
+ bool mMatrixOrPivotDirty;
bool mCaching;
} mPrimitiveFields;
@@ -506,7 +461,6 @@
SkMatrix* mTransformMatrix;
Sk3DView mTransformCamera;
- SkMatrix* mTransformMatrix3D;
SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
SkRegion::Op mClipPathOp;
} mComputedFields;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 7f1c5c7..4513ead 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -43,6 +43,7 @@
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
+import android.hardware.usb.UsbManager;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.os.Binder;
@@ -528,6 +529,7 @@
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
// TODO merge orientation and rotation
@@ -3975,7 +3977,8 @@
(device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
setBluetoothA2dpOnInt(true);
}
- boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
+ boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+ ((device & AudioSystem.DEVICE_IN_ALL_USB) != 0);
handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
if (state != 0) {
if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
@@ -4080,20 +4083,41 @@
}
}
}
- } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
- action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+ } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
state = intent.getIntExtra("state", 0);
+
int alsaCard = intent.getIntExtra("card", -1);
int alsaDevice = intent.getIntExtra("device", -1);
+
String params = (alsaCard == -1 && alsaDevice == -1 ? ""
: "card=" + alsaCard + ";device=" + alsaDevice);
- device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
- AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
- Log.v(TAG, "Broadcast Receiver: Got "
- + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
- "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
- + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
+
+ // Playback Device
+ device = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
setWiredDeviceConnectionState(device, state, params);
+ } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+ state = intent.getIntExtra("state", 0);
+
+ int alsaCard = intent.getIntExtra("card", -1);
+ int alsaDevice = intent.getIntExtra("device", -1);
+ boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
+ boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
+ boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
+
+ String params = (alsaCard == -1 && alsaDevice == -1 ? ""
+ : "card=" + alsaCard + ";device=" + alsaDevice);
+
+ // Playback Device
+ if (hasPlayback) {
+ device = AudioSystem.DEVICE_OUT_USB_DEVICE;
+ setWiredDeviceConnectionState(device, state, params);
+ }
+
+ // Capture Device
+ if (hasCapture) {
+ device = AudioSystem.DEVICE_IN_USB_DEVICE;
+ setWiredDeviceConnectionState(device, state, params);
+ }
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
boolean broadcast = false;
int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
@@ -4199,7 +4223,7 @@
mStreamStates[AudioSystem.STREAM_MUSIC], 0);
}
}
- }
+ } // end class AudioServiceBroadcastReceiver
//==========================================================================================
// RemoteControlDisplay / RemoteControlClient / Remote info
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9c67bae..327c10c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -288,6 +288,8 @@
DEVICE_IN_USB_DEVICE |
DEVICE_IN_DEFAULT);
public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
+ DEVICE_IN_USB_DEVICE);
// device states, must match AudioSystem::device_connection_state
public static final int DEVICE_STATE_UNAVAILABLE = 0;
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
index 2446c2f..fbf2eab 100644
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -47,6 +47,8 @@
import android.os.SystemProperties;
import android.os.Environment;
+import libcore.io.IoUtils;
+
/**
* The VideoEditor implementation {@hide}
*/
@@ -1859,15 +1861,15 @@
}
}
+ FileOutputStream stream = null;
try {
- FileOutputStream stream = new FileOutputStream(mProjectPath + "/"
- + THUMBNAIL_FILENAME);
+ stream = new FileOutputStream(mProjectPath + "/" + THUMBNAIL_FILENAME);
projectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
stream.flush();
- stream.close();
} catch (IOException e) {
throw new IllegalArgumentException ("Error creating project thumbnail");
} finally {
+ IoUtils.closeQuietly(stream);
projectBitmap.recycle();
}
}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 76c6eda..fb4de9e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -153,3 +153,23 @@
{
return static_cast<Sensor const*>(sensor)->getMinDelay();
}
+
+int ASensor_getFifoMaxEventCount(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getFifoMaxEventCount();
+}
+
+int ASensor_getFifoReservedEventCount(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getFifoReservedEventCount();
+}
+
+const char* ASensor_getStringType(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getStringType().string();
+}
+
+const char* ASensor_getRequiredPermission(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getRequiredPermission().string();
+}
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 4738049..d20b269 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -18,6 +18,8 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- App label in the manifest -->
+ <string name="app_name">Keyguard</string>
<!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard.
Displayed in one line in a large font. -->
<string name="keyguard_password_enter_pin_code">Type PIN code</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
index b085211..95ab8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
@@ -24,9 +24,6 @@
* P3 (1.0, 1.0)
*
* Values sampled with x at regular intervals between 0 and 1.
- *
- * These values were generated using:
- * ./scripts/bezier_interpolator_values_gen.py 0.4 0.2
*/
private static final float[] VALUES = new float[] {
0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 21460bb..8949663 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -83,6 +83,7 @@
res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
}
+ /** Updates the system insets */
public void updateSystemInsets(Rect insets) {
systemInsets.set(insets);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 21e2c1d..d2de185 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -134,9 +134,9 @@
/* Notifies when a task has been removed from the stack */
public void onStackTaskRemoved(TaskStack stack, Task t);
/** Notifies when the stack was filtered */
- public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t);
+ public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t);
/** Notifies when the stack was un-filtered */
- public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack);
+ public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
}
Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 728aaad..88fb972 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -26,6 +26,7 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Region;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -45,6 +46,7 @@
import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList;
+import java.util.HashMap;
/* The visual representation of a task stack view */
@@ -76,9 +78,6 @@
OverScroller mScroller;
ObjectAnimator mScrollAnimator;
- // Filtering
- AnimatorSet mFilterChildrenAnimator;
-
// Optimizations
int mHwLayersRefCount;
int mStackViewsAnimationDuration;
@@ -645,163 +644,22 @@
requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement));
}
- @Override
- public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack,
- Task filteredTask) {
- // NOTE: This code assumes that the current (unfiltered) stack is a superset of the new
- // (filtered) stack
- // XXX: Use HW Layers
- // Stash the scroll and filtered task for us to restore to when we unfilter
- mStashedScroll = getStackScroll();
-
- // Compute the transforms of the items in the current stack
- final ArrayList<TaskViewTransform> curTaskTransforms =
- getStackTransforms(curStack, mStashedScroll, null, true);
-
- // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better
- updateMinMaxScroll(false);
- float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
- setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight));
- boundScrollRaw();
-
- // Compute the transforms of the items in the new stack after setting the new scroll
- final ArrayList<TaskViewTransform> taskTransforms =
- getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
-
- // Animate all of the existing views on screen either out of view (if they are not visible
- // in the new stack) or to their final positions in the new stack
- final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>();
- final ArrayList<Task> tasks = mStack.getTasks();
- ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
- int childCount = getChildCount();
- int movement = 0;
- for (int i = 0; i < childCount; i++) {
- TaskView tv = (TaskView) getChildAt(i);
- Task task = tv.getTask();
- TaskViewTransform toTransform;
- int taskIndex = tasks.indexOf(task);
-
- boolean willBeInvisible = (taskIndex < 0) || !taskTransforms.get(taskIndex).visible;
- if (willBeInvisible) {
- // Compose a new transform that fades and slides the task out of view
- TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task));
- toTransform = new TaskViewTransform(fromTransform);
- tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
- tv.prepareTaskTransformForFilterTaskHidden(toTransform);
-
- childrenToReturnToPool.add(tv);
- } else {
- toTransform = taskTransforms.get(taskIndex);
-
- // Use the movement of the visible views to calculate the duration of the animation
- movement = Math.max(movement,
- Math.abs(toTransform.translationY - (int) tv.getTranslationY()));
- }
- childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
- }
-
- // Cancel the previous animation
- if (mFilterChildrenAnimator != null) {
- mFilterChildrenAnimator.cancel();
- mFilterChildrenAnimator.removeAllListeners();
- }
-
- // Create a new animation for the existing children
- final RecentsConfiguration config = RecentsConfiguration.getInstance();
- mFilterChildrenAnimator = new AnimatorSet();
- mFilterChildrenAnimator.setDuration(
- Utilities.calculateTranslationAnimationDuration(movement,
- config.filteringCurrentViewsMinAnimDuration));
- mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
- mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
- boolean isCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- isCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (isCancelled) return;
-
- // Return all the removed children to the view pool
- for (TaskView tv : childrenToReturnToPool) {
- mViewPool.returnViewToPool(tv);
- }
-
- // For views that are not already visible, animate them in
- ArrayList<Animator> newViewsAnims = new ArrayList<Animator>();
- int taskCount = tasks.size();
- int movement = 0;
- int offset = 0;
- for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- TaskViewTransform toTransform = taskTransforms.get(i);
- if (toTransform.visible) {
- TaskViewTransform fromTransform =
- curTaskTransforms.get(curStack.indexOf(task));
- TaskView tv = getChildViewForTask(task);
- if (tv == null) {
- tv = mViewPool.pickUpViewFromPool(task, task);
- // Compose a new transform that fades and slides the new task in
- fromTransform = new TaskViewTransform(toTransform);
- tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
- tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-
- Animator anim = tv.getAnimatorToTaskTransform(toTransform);
- anim.setStartDelay(offset *
- Constants.Values.TaskStackView.FilterStartDelay);
- newViewsAnims.add(anim);
-
- // Use the movement of the newly visible views to calculate the duration
- // of the animation
- movement = Math.max(movement, Math.abs(toTransform.translationY -
- fromTransform.translationY));
- offset++;
- }
- }
-
- // Animate the new views in
- mFilterChildrenAnimator = new AnimatorSet();
- mFilterChildrenAnimator.setDuration(
- Utilities.calculateTranslationAnimationDuration(movement,
- config.filteringNewViewsMinAnimDuration));
- mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
- mFilterChildrenAnimator.playTogether(newViewsAnims);
- mFilterChildrenAnimator.start();
- }
- invalidate();
- }
- });
- mFilterChildrenAnimator.playTogether(childViewAnims);
- mFilterChildrenAnimator.start();
- }
-
- @Override
- public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) {
- // Compute the transforms of the items in the current stack
- final int curScroll = getStackScroll();
- final ArrayList<TaskViewTransform> curTaskTransforms =
- getStackTransforms(curStack, curScroll, null, true);
-
- // Restore the stashed scroll
- updateMinMaxScroll(false);
- setStackScrollRaw(mStashedScroll);
- boundScrollRaw();
-
- // Compute the transforms of the items in the new stack after restoring the stashed scroll
- final ArrayList<TaskViewTransform> taskTransforms =
- getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
-
+ /**
+ * Creates the animations for all the children views that need to be removed or to move views
+ * to their un/filtered position when we are un/filtering a stack, and returns the duration
+ * for these animations.
+ */
+ int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks,
+ ArrayList<TaskViewTransform> curTaskTransforms,
+ ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms,
+ HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
+ ArrayList<TaskView> childrenToRemoveOut,
+ RecentsConfiguration config) {
// Animate all of the existing views out of view (if they are not in the visible range in
// the new stack) or to their final positions in the new stack
- final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
- final ArrayList<Task> tasks = mStack.getTasks();
- ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
- int childCount = getChildCount();
int movement = 0;
+ int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
TaskView tv = (TaskView) getChildAt(i);
Task task = tv.getTask();
@@ -811,104 +669,166 @@
// If the view is no longer visible, then we should just animate it out
boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible;
if (willBeInvisible) {
- toTransform = new TaskViewTransform(taskTransforms.get(taskIndex));
+ if (taskIndex < 0) {
+ toTransform = curTaskTransforms.get(curTasks.indexOf(task));
+ } else {
+ toTransform = new TaskViewTransform(taskTransforms.get(taskIndex));
+ }
tv.prepareTaskTransformForFilterTaskVisible(toTransform);
- childrenToRemove.add(tv);
+ childrenToRemoveOut.add(tv);
} else {
toTransform = taskTransforms.get(taskIndex);
// Use the movement of the visible views to calculate the duration of the animation
movement = Math.max(movement, Math.abs(toTransform.translationY -
(int) tv.getTranslationY()));
}
-
- Animator anim = tv.getAnimatorToTaskTransform(toTransform);
- childViewAnims.add(anim);
+ childViewTransformsOut.put(tv, new Pair(0, toTransform));
}
+ return Utilities.calculateTranslationAnimationDuration(movement,
+ config.filteringCurrentViewsMinAnimDuration);
+ }
- // Cancel the previous animation
- if (mFilterChildrenAnimator != null) {
- mFilterChildrenAnimator.cancel();
- mFilterChildrenAnimator.removeAllListeners();
+ /**
+ * Creates the animations for all the children views that need to be animated in when we are
+ * un/filtering a stack, and returns the duration for these animations.
+ */
+ int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks,
+ ArrayList<TaskViewTransform> taskTransforms,
+ HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
+ RecentsConfiguration config) {
+ int offset = 0;
+ int movement = 0;
+ int taskCount = tasks.size();
+ for (int i = taskCount - 1; i >= 0; i--) {
+ Task task = tasks.get(i);
+ TaskViewTransform toTransform = taskTransforms.get(i);
+ if (toTransform.visible) {
+ TaskView tv = getChildViewForTask(task);
+ if (tv == null) {
+ // For views that are not already visible, animate them in
+ tv = mViewPool.pickUpViewFromPool(task, task);
+
+ // Compose a new transform to fade and slide the new task in
+ TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
+ tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
+ tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+
+ int startDelay = offset *
+ Constants.Values.TaskStackView.FilterStartDelay;
+ childViewTransformsOut.put(tv, new Pair(startDelay, toTransform));
+
+ // Use the movement of the new views to calculate the duration of the animation
+ movement = Math.max(movement,
+ Math.abs(toTransform.translationY - fromTransform.translationY));
+ offset++;
+ }
+ }
}
+ return Utilities.calculateTranslationAnimationDuration(movement,
+ config.filteringNewViewsMinAnimDuration);
+ }
- // Create a new animation for the existing children
+ /** Orchestrates the animations of the current child views and any new views. */
+ void doFilteringAnimation(ArrayList<Task> curTasks,
+ ArrayList<TaskViewTransform> curTaskTransforms,
+ final ArrayList<Task> tasks,
+ final ArrayList<TaskViewTransform> taskTransforms) {
final RecentsConfiguration config = RecentsConfiguration.getInstance();
- mFilterChildrenAnimator = new AnimatorSet();
- mFilterChildrenAnimator.setDuration(
- Utilities.calculateTranslationAnimationDuration(movement,
- config.filteringCurrentViewsMinAnimDuration));
- mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
- mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
- boolean isCancelled;
- @Override
- public void onAnimationCancel(Animator animation) {
- isCancelled = true;
- }
+ // Calculate the transforms to animate out all the existing views if they are not in the
+ // new visible range (or to their final positions in the stack if they are)
+ final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
+ final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms =
+ new HashMap<TaskView, Pair<Integer, TaskViewTransform>>();
+ int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks,
+ taskTransforms, childViewTransforms, childrenToRemove, config);
- @Override
- public void onAnimationEnd(Animator animation) {
- if (isCancelled) return;
+ // If all the current views are in the visible range of the new stack, then don't wait for
+ // views to animate out and animate all the new views into their place
+ final boolean unifyNewViewAnimation = childrenToRemove.isEmpty();
+ if (unifyNewViewAnimation) {
+ int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms,
+ childViewTransforms, config);
+ duration = Math.max(duration, inDuration);
+ }
- // Return all the removed children to the view pool
- for (TaskView tv : childrenToRemove) {
- mViewPool.returnViewToPool(tv);
- }
+ // Animate all the views to their final transforms
+ for (final TaskView tv : childViewTransforms.keySet()) {
+ Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
+ tv.animate().cancel();
+ tv.animate()
+ .setStartDelay(t.first)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ childViewTransforms.remove(tv);
+ if (childViewTransforms.isEmpty()) {
+ // Return all the removed children to the view pool
+ for (TaskView tv : childrenToRemove) {
+ mViewPool.returnViewToPool(tv);
+ }
- // Increment the hw layers ref count
- addHwLayersRefCount("unfilteredNewViews");
-
- // For views that are not already visible, animate them in
- ArrayList<Animator> newViewAnims = new ArrayList<Animator>();
- int taskCount = tasks.size();
- int movement = 0;
- int offset = 0;
- for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- TaskViewTransform toTransform = taskTransforms.get(i);
- if (toTransform.visible) {
- TaskView tv = getChildViewForTask(task);
- if (tv == null) {
- // For views that are not already visible, animate them in
- tv = mViewPool.pickUpViewFromPool(task, task);
-
- // Compose a new transform to fade and slide the new task in
- TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
- tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
- tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-
- Animator anim = tv.getAnimatorToTaskTransform(toTransform);
- anim.setStartDelay(offset *
- Constants.Values.TaskStackView.FilterStartDelay);
- newViewAnims.add(anim);
- // Use the movement of the newly visible views to calculate the duration
- // of the animation
- movement = Math.max(movement,
- Math.abs(toTransform.translationY - fromTransform.translationY));
- offset++;
+ if (!unifyNewViewAnimation) {
+ // For views that are not already visible, animate them in
+ childViewTransforms.clear();
+ int duration = getEnterTransformsForFilterAnimation(tasks,
+ taskTransforms, childViewTransforms, config);
+ for (final TaskView tv : childViewTransforms.keySet()) {
+ Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
+ tv.animate().setStartDelay(t.first);
+ tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+ }
+ }
+ }
}
- }
- }
+ });
+ tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+ }
+ }
- // Run the animation
- mFilterChildrenAnimator = new AnimatorSet();
- mFilterChildrenAnimator.setDuration(
- Utilities.calculateTranslationAnimationDuration(movement,
- config.filteringNewViewsMinAnimDuration));
- mFilterChildrenAnimator.playTogether(newViewAnims);
- mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Decrement the hw layers ref count
- decHwLayersRefCount("unfilteredNewViews");
- }
- });
- mFilterChildrenAnimator.start();
- invalidate();
- }
- });
- mFilterChildrenAnimator.playTogether(childViewAnims);
- mFilterChildrenAnimator.start();
+ @Override
+ public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks,
+ Task filteredTask) {
+ // Stash the scroll and filtered task for us to restore to when we unfilter
+ mStashedScroll = getStackScroll();
+
+ // Calculate the current task transforms
+ ArrayList<TaskViewTransform> curTaskTransforms =
+ getStackTransforms(curTasks, getStackScroll(), null, true);
+
+ // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better
+ updateMinMaxScroll(false);
+ float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
+ setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight));
+ boundScrollRaw();
+
+ // Compute the transforms of the items in the new stack after setting the new scroll
+ final ArrayList<Task> tasks = mStack.getTasks();
+ final ArrayList<TaskViewTransform> taskTransforms =
+ getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
+
+ // Animate
+ doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms);
+ }
+
+ @Override
+ public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) {
+ // Calculate the current task transforms
+ final ArrayList<TaskViewTransform> curTaskTransforms =
+ getStackTransforms(curTasks, getStackScroll(), null, true);
+
+ // Restore the stashed scroll
+ updateMinMaxScroll(false);
+ setStackScrollRaw(mStashedScroll);
+ boundScrollRaw();
+
+ // Compute the transforms of the items in the new stack after restoring the stashed scroll
+ final ArrayList<Task> tasks = mStack.getTasks();
+ final ArrayList<TaskViewTransform> taskTransforms =
+ getStackTransforms(tasks, getStackScroll(), null, true);
+
+ // Animate
+ doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms);
// Clear the saved vars
mStashedScroll = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index a3056ec..b4100127 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,21 +16,13 @@
package com.android.systemui.recents.views;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Path;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import com.android.systemui.R;
import com.android.systemui.recents.BakedBezierInterpolator;
-import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
@@ -115,18 +107,6 @@
}
}
- /** Returns an animator to animate this task to the specified transform */
- Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) {
- AnimatorSet anims = new AnimatorSet();
- anims.playTogether(
- ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY),
- ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale),
- ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale),
- ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha)
- );
- return anims;
- }
-
/** Resets this view's properties */
void resetViewProperties() {
setTranslationX(0f);
@@ -136,12 +116,20 @@
setAlpha(1f);
}
+ /**
+ * When we are un/filtering, this method will set up the transform that we are animating to,
+ * in order to hide the task.
+ */
void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
// Fade the view out and slide it away
toTransform.alpha = 0f;
toTransform.translationY += 200;
}
+ /**
+ * When we are un/filtering, this method will setup the transform that we are animating from,
+ * in order to show the task.
+ */
void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
// Fade the view in
fromTransform.alpha = 0f;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ccdacea..216f6a4 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -986,7 +986,7 @@
initializeHdmiState();
// Match current screen state.
- if (mPowerManager.isScreenOn()) {
+ if (mPowerManager.isInteractive()) {
screenTurningOn(null);
} else {
screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
@@ -2357,7 +2357,7 @@
}
private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
- int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
+ int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
win, fallbackEvent, policyFlags);
@@ -3801,12 +3801,13 @@
/** {@inheritDoc} */
@Override
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
+ final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
@@ -3818,7 +3819,7 @@
// This will prevent any keys other than the power button from waking the screen
// when the keyguard is hidden by another activity.
final boolean keyguardActive = (mKeyguardDelegate == null ? false :
- (isScreenOn ?
+ (interactive ?
mKeyguardDelegate.isShowingAndNotHidden() :
mKeyguardDelegate.isShowing()));
@@ -3830,7 +3831,7 @@
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
- + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
+ + " interactive=" + interactive + " keyguardActive=" + keyguardActive
+ " policyFlags=" + Integer.toHexString(policyFlags));
}
@@ -3839,18 +3840,11 @@
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
}
- // Basic policy based on screen state and keyguard.
- // FIXME: This policy isn't quite correct. We shouldn't care whether the screen
- // is on or off, really. We should care about whether the device is in an
- // interactive state or is in suspend pretending to be "off".
- // The primary screen might be turned off due to proximity sensor or
- // because we are presenting media on an auxiliary screen or remotely controlling
- // the device some other way (which is why we have an exemption here for injected
- // events).
+ // Basic policy based on interactive state.
int result;
boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
| WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
- if (isScreenOn || (isInjected && !isWakeKey)) {
+ if (interactive || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
} else {
@@ -3875,7 +3869,7 @@
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
- if (isScreenOn && !mVolumeDownKeyTriggered
+ if (interactive && !mVolumeDownKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeDownKeyTriggered = true;
mVolumeDownKeyTime = event.getDownTime();
@@ -3889,7 +3883,7 @@
}
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
if (down) {
- if (isScreenOn && !mVolumeUpKeyTriggered
+ if (interactive && !mVolumeUpKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeUpKeyTriggered = true;
cancelPendingPowerKeyAction();
@@ -3957,7 +3951,7 @@
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
- interceptPowerKeyDown(!isScreenOn || hungUp);
+ interceptPowerKeyDown(!interactive || hungUp);
} else {
if (interceptPowerKeyUp(canceled)) {
if ((mEndcallBehavior
@@ -3979,12 +3973,12 @@
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
+ boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
event.getDownTime(), isImmersiveMode(mLastSystemUiFlags));
if (panic) {
mHandler.post(mRequestTransientNav);
}
- if (isScreenOn && !mPowerKeyTriggered
+ if (interactive && !mPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mPowerKeyTriggered = true;
mPowerKeyTime = event.getDownTime();
@@ -4001,7 +3995,7 @@
telephonyService.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
- && telephonyService.isOffhook() && isScreenOn) {
+ && telephonyService.isOffhook() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
hungUp = telephonyService.endCall();
@@ -4010,7 +4004,7 @@
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
- interceptPowerKeyDown(!isScreenOn || hungUp
+ interceptPowerKeyDown(!interactive || hungUp
|| mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
} else {
mPowerKeyTriggered = false;
@@ -4143,15 +4137,12 @@
/** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
- int result = 0;
-
- final boolean isWakeMotion = (policyFlags
- & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
- if (isWakeMotion) {
- mPowerManager.wakeUp(whenNanos / 1000000);
- }
- return result;
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+ // We already know this is a wake motion so just wake up.
+ // Note that we would observe policyFlags containing
+ // FLAG_WAKE and FLAG_INTERACTIVE here.
+ mPowerManager.wakeUp(whenNanos / 1000000);
+ return 0;
}
void dispatchMediaKeyWithWakeLock(KeyEvent event) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 53ac063..038686b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -166,8 +166,6 @@
private final Point mTempPoint = new Point();
- private final Display mDefaultDisplay;
-
private final PackageManager mPackageManager;
private final WindowManagerInternal mWindowManagerService;
@@ -176,7 +174,7 @@
private final MainHandler mMainHandler;
- private Service mQueryBridge;
+ private InteractionBridge mInteractionBridge;
private AlertDialog mEnableTouchExplorationDialog;
@@ -232,10 +230,6 @@
mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
mSecurityPolicy = new SecurityPolicy();
mMainHandler = new MainHandler(mContext.getMainLooper());
- //TODO: (multi-display) We need to support multiple displays.
- DisplayManager displayManager = (DisplayManager)
- mContext.getSystemService(Context.DISPLAY_SERVICE);
- mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
registerBroadcastReceivers();
new AccessibilityContentObserver(mMainHandler).register(
context.getContentResolver());
@@ -401,7 +395,8 @@
return true; // yes, recycle the event
}
if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
- mSecurityPolicy.updateActiveWindowLocked(event.getWindowId(), event.getEventType());
+ mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(),
+ event.getSourceNodeId(), event.getEventType());
mSecurityPolicy.updateEventSourceLocked(event);
notifyAccessibilityServicesDelayedLocked(event, false);
notifyAccessibilityServicesDelayedLocked(event, true);
@@ -725,46 +720,8 @@
* @return Whether accessibility focus was found and the bounds are populated.
*/
// TODO: (multi-display) Make sure this works for multiple displays.
- boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
- // Instead of keeping track of accessibility focus events per
- // window to be able to find the focus in the active window,
- // we take a stateless approach and look it up. This is fine
- // since we do this only when the user clicks/long presses.
- Service service = getQueryBridge();
- final int connectionId = service.mId;
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- client.addConnection(connectionId, service);
- try {
- AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
- .getRootInActiveWindow(connectionId);
- if (root == null) {
- return false;
- }
- AccessibilityNodeInfo focus = root.findFocus(
- AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
- if (focus == null) {
- return false;
- }
- focus.getBoundsInScreen(outBounds);
-
- MagnificationSpec spec = service.getCompatibleMagnificationSpec(focus.getWindowId());
- if (spec != null && !spec.isNop()) {
- outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
- outBounds.scale(1 / spec.scale);
- }
-
- // Clip to the window rectangle.
- Rect windowBounds = mTempRect;
- getActiveWindowBounds(windowBounds);
- outBounds.intersect(windowBounds);
- // Clip to the screen rectangle.
- mDefaultDisplay.getRealSize(mTempPoint);
- outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y);
-
- return true;
- } finally {
- client.removeConnection(connectionId);
- }
+ boolean getAccessibilityFocusBounds(Rect outBounds) {
+ return getInteractionBridgeLocked().getAccessibilityFocusBoundsNotLocked(outBounds);
}
/**
@@ -855,14 +812,11 @@
}
}
- private Service getQueryBridge() {
- if (mQueryBridge == null) {
- AccessibilityServiceInfo info = new AccessibilityServiceInfo();
- info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
- mQueryBridge = new Service(UserHandle.USER_NULL,
- sFakeAccessibilityServiceComponentName, info);
+ private InteractionBridge getInteractionBridgeLocked() {
+ if (mInteractionBridge == null) {
+ mInteractionBridge = new InteractionBridge();
}
- return mQueryBridge;
+ return mInteractionBridge;
}
private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
@@ -1333,9 +1287,10 @@
private void onUserStateChangedLocked(UserState userState) {
// TODO: Remove this hack
mInitialized = true;
- updateLegacyCapabilities(userState);
+ updateLegacyCapabilitiesLocked(userState);
updateServicesLocked(userState);
- updateWindowsForAccessibilityCallback(userState);
+ updateWindowsForAccessibilityCallbackLocked(userState);
+ updateAccessibilityFocusBehaviorLocked(userState);
updateFilterKeyEventsLocked(userState);
updateTouchExplorationLocked(userState);
updateEnhancedWebAccessibilityLocked(userState);
@@ -1344,7 +1299,29 @@
scheduleUpdateClientsIfNeededLocked(userState);
}
- private void updateWindowsForAccessibilityCallback(UserState userState) {
+ private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
+ // If there is no service that can operate with interactive windows
+ // then we keep the old behavior where a window loses accessibility
+ // focus if it is no longer active. This still changes the behavior
+ // for services that do not operate with interactive windows and run
+ // at the same time as the one(s) which does. In practice however,
+ // there is only one service that uses accessibility focus and it
+ // is typically the one that operates with interactive windows, So,
+ // this is fine. Note that to allow a service to work across windows
+ // we have to allow accessibility focus stay in any of them. Sigh...
+ List<Service> boundServices = userState.mBoundServices;
+ final int boundServiceCount = boundServices.size();
+ for (int i = 0; i < boundServiceCount; i++) {
+ Service boundService = boundServices.get(i);
+ if (boundService.canRetrieveInteractiveWindowsLocked()) {
+ userState.mAccessibilityFocusOnlyInActiveWindow = false;
+ return;
+ }
+ }
+ userState.mAccessibilityFocusOnlyInActiveWindow = true;
+ }
+
+ private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
if (userState.mIsAccessibilityEnabled) {
// We observe windows for accessibility only if there is at least
// one bound service that can retrieve window content that specified
@@ -1357,8 +1334,7 @@
final int boundServiceCount = boundServices.size();
for (int i = 0; i < boundServiceCount; i++) {
Service boundService = boundServices.get(i);
- if (mSecurityPolicy.canRetrieveWindowContentLocked(boundService)
- && boundService.mRetrieveInteractiveWindows) {
+ if (boundService.canRetrieveInteractiveWindowsLocked()) {
boundServiceCanRetrieveInteractiveWindows = true;
break;
}
@@ -1381,7 +1357,7 @@
}
}
- private void updateLegacyCapabilities(UserState userState) {
+ private void updateLegacyCapabilitiesLocked(UserState userState) {
// Up to JB-MR1 we had a white list with services that can enable touch
// exploration. When a service is first started we show a dialog to the
// use to get a permission to white list the service.
@@ -1582,6 +1558,18 @@
DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
}
+ private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
+ IBinder windowToken = mGlobalWindowTokens.get(windowId);
+ if (windowToken == null) {
+ windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+ }
+ if (windowToken != null) {
+ return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
+ windowToken);
+ }
+ return null;
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
@@ -1658,6 +1646,7 @@
public static final int MSG_UPDATE_INPUT_FILTER = 6;
public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
+ public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
public MainHandler(Looper looper) {
super(looper);
@@ -1713,6 +1702,15 @@
Service service = (Service) msg.obj;
showEnableTouchExplorationDialog(service);
} break;
+
+ case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
+ final int windowId = msg.arg1;
+ InteractionBridge bridge;
+ synchronized (mLock) {
+ bridge = getInteractionBridgeLocked();
+ }
+ bridge.clearAccessibilityFocusNotLocked(windowId);
+ } break;
}
}
@@ -1981,6 +1979,11 @@
}
}
+ public boolean canRetrieveInteractiveWindowsLocked() {
+ return mSecurityPolicy.canRetrieveWindowContentLocked(this)
+ && mRetrieveInteractiveWindows;
+ }
+
@Override
public void setServiceInfo(AccessibilityServiceInfo info) {
final long identity = Binder.clearCallingIdentity();
@@ -2109,7 +2112,7 @@
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
- MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+ MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId,
viewIdResName, interactionId, callback, mFetchFlags, interrogatingPid,
@@ -2153,7 +2156,7 @@
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
- MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+ MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
@@ -2197,7 +2200,7 @@
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
- MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+ MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
interactionId, callback, mFetchFlags | flags, interrogatingPid,
@@ -2227,7 +2230,8 @@
if (resolvedUserId != mCurrentUserId) {
return false;
}
- resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
+ resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
+ accessibilityWindowId, focusType);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
@@ -2241,14 +2245,14 @@
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
- MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+ MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
mFetchFlags, interrogatingPid, interrogatingTid, spec);
return true;
} catch (RemoteException re) {
if (DEBUG) {
- Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
+ Slog.e(LOG_TAG, "Error calling findFocus()");
}
} finally {
Binder.restoreCallingIdentity(identityToken);
@@ -2284,7 +2288,7 @@
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
- MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+ MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
mFetchFlags, interrogatingPid, interrogatingTid, spec);
@@ -2729,16 +2733,18 @@
return accessibilityWindowId;
}
- private MagnificationSpec getCompatibleMagnificationSpec(int windowId) {
- IBinder windowToken = mGlobalWindowTokens.get(windowId);
- if (windowToken == null) {
- windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+ private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
+ if (windowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
+ return mSecurityPolicy.mActiveWindowId;
}
- if (windowToken != null) {
- return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
- windowToken);
+ if (windowId == AccessibilityNodeInfo.ANY_WINDOW_ID) {
+ if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
+ return mSecurityPolicy.mFocusedWindowId;
+ } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
+ return mSecurityPolicy.mAccessibilityFocusedWindowId;
+ }
}
- return null;
+ return windowId;
}
private final class InvocationHandler extends Handler {
@@ -3031,7 +3037,86 @@
}
}
+ private final class InteractionBridge {
+ private final Display mDefaultDisplay;
+ private final int mConnectionId;
+ private final AccessibilityInteractionClient mClient;
+
+ public InteractionBridge() {
+ AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+ info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
+ info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+ info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+ Service service = new Service(UserHandle.USER_NULL,
+ sFakeAccessibilityServiceComponentName, info);
+
+ mConnectionId = service.mId;
+
+ mClient = AccessibilityInteractionClient.getInstance();
+ mClient.addConnection(mConnectionId, service);
+
+ //TODO: (multi-display) We need to support multiple displays.
+ DisplayManager displayManager = (DisplayManager)
+ mContext.getSystemService(Context.DISPLAY_SERVICE);
+ mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ }
+
+ public void clearAccessibilityFocusNotLocked(int windowId) {
+ AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId);
+ if (focus != null) {
+ focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ }
+ }
+
+ public boolean getAccessibilityFocusBoundsNotLocked(Rect outBounds) {
+ AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
+ if (focus == null) {
+ return false;
+ }
+
+ synchronized (mLock) {
+ focus.getBoundsInScreen(outBounds);
+
+ MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
+ if (spec != null && !spec.isNop()) {
+ outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
+ outBounds.scale(1 / spec.scale);
+ }
+
+ // Clip to the window rectangle.
+ Rect windowBounds = mTempRect;
+ getActiveWindowBounds(windowBounds);
+ outBounds.intersect(windowBounds);
+
+ // Clip to the screen rectangle.
+ mDefaultDisplay.getRealSize(mTempPoint);
+ outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y);
+
+ return true;
+ }
+ }
+
+ private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
+ final int focusedWindowId;
+ synchronized (mLock) {
+ focusedWindowId = mSecurityPolicy.mAccessibilityFocusedWindowId;
+ if (focusedWindowId == SecurityPolicy.INVALID_WINDOW_ID) {
+ return null;
+ }
+ }
+ return getAccessibilityFocusNotLocked(focusedWindowId);
+ }
+
+ private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) {
+ return mClient.findFocus(mConnectionId,
+ windowId, AccessibilityNodeInfo.ROOT_NODE_ID,
+ AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+ }
+ }
+
final class SecurityPolicy {
+ public static final int INVALID_WINDOW_ID = -1;
+
private static final int VALID_ACTIONS =
AccessibilityNodeInfo.ACTION_CLICK
| AccessibilityNodeInfo.ACTION_LONG_CLICK
@@ -3075,8 +3160,11 @@
public final List<AccessibilityWindowInfo> mWindows =
new ArrayList<AccessibilityWindowInfo>();
- public int mActiveWindowId;
- public int mFocusedWindowId;
+ public int mActiveWindowId = INVALID_WINDOW_ID;
+ public int mFocusedWindowId = INVALID_WINDOW_ID;
+ public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
+ public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
public AccessibilityEvent mShowingFocusedWindowEvent;
private boolean mTouchInteractionInProgress;
@@ -3129,9 +3217,9 @@
mWindows.remove(i).recycle();
}
- mFocusedWindowId = -1;
+ mFocusedWindowId = INVALID_WINDOW_ID;
if (!mTouchInteractionInProgress) {
- mActiveWindowId = -1;
+ mActiveWindowId = INVALID_WINDOW_ID;
}
// If the active window goes away while the user is touch exploring we
@@ -3159,7 +3247,7 @@
}
if (mTouchInteractionInProgress && activeWindowGone) {
- mActiveWindowId = -1;
+ mActiveWindowId = INVALID_WINDOW_ID;
}
// Focused window may change the active one, so set the
@@ -3193,7 +3281,8 @@
}
}
- public void updateActiveWindowLocked(int windowId, int eventType) {
+ public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId,
+ int eventType) {
// The active window is either the window that has input focus or
// the window that the user is currently touching. If the user is
// touching a window that does not have input focus as soon as the
@@ -3228,6 +3317,29 @@
}
}
} break;
+
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+ synchronized (mLock) {
+ if (mAccessibilityFocusedWindowId != windowId) {
+ mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
+ mAccessibilityFocusedWindowId, 0).sendToTarget();
+ mAccessibilityFocusedWindowId = windowId;
+ mAccessibilityFocusNodeId = nodeId;
+ }
+ }
+ } break;
+
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+ synchronized (mLock) {
+ if (mAccessibilityFocusNodeId == nodeId) {
+ mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ }
+ if (mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID
+ && mAccessibilityFocusedWindowId == windowId) {
+ mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
+ }
+ }
+ } break;
}
}
@@ -3248,7 +3360,19 @@
// (they are a result of user touching the screen) so change of
// the active window before all hover accessibility events from
// the touched window are delivered is fine.
+ final int oldActiveWindow = mSecurityPolicy.mActiveWindowId;
setActiveWindowLocked(mFocusedWindowId);
+
+ // If there is no service that can operate with active windows
+ // we keep accessibility focus behavior to constrain it only in
+ // the active window. Look at updateAccessibilityFocusBehaviorLocked
+ // for details.
+ if (oldActiveWindow != mSecurityPolicy.mActiveWindowId
+ && mAccessibilityFocusedWindowId == oldActiveWindow
+ && getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) {
+ mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
+ oldActiveWindow, 0).sendToTarget();
+ }
}
}
@@ -3403,6 +3527,7 @@
public boolean mIsDisplayMagnificationEnabled;
public boolean mIsFilterKeyEventsEnabled;
public boolean mHasDisplayColorAdjustment;
+ public boolean mAccessibilityFocusOnlyInActiveWindow;
private Service mUiAutomationService;
private IAccessibilityServiceClient mUiAutomationServiceClient;
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 43f12eb..ac0ca0a 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -1159,7 +1159,7 @@
// No last touch explored event but there is accessibility focus in
// the active window. We click in the middle of the focus bounds.
Rect focusBounds = mTempRect;
- if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ if (mAms.getAccessibilityFocusBounds(focusBounds)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();
} else {
@@ -1177,7 +1177,7 @@
mAms.getActiveWindowBounds(activeWindowBounds);
if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
Rect focusBounds = mTempRect;
- if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ if (mAms.getAccessibilityFocusBounds(focusBounds)) {
if (!focusBounds.contains(clickLocationX, clickLocationY)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();
@@ -1332,7 +1332,7 @@
// No last touch explored event but there is accessibility focus in
// the active window. We click in the middle of the focus bounds.
Rect focusBounds = mTempRect;
- if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ if (mAms.getAccessibilityFocusBounds(focusBounds)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();
} else {
@@ -1350,7 +1350,7 @@
mAms.getActiveWindowBounds(activeWindowBounds);
if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
Rect focusBounds = mTempRect;
- if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ if (mAms.getAccessibilityFocusBounds(focusBounds)) {
if (!focusBounds.contains(clickLocationX, clickLocationY)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
new file mode 100644
index 0000000..eb0ae6a
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+/**
+ * Interface used to update the actual display state.
+ */
+public interface DisplayBlanker {
+ void requestDisplayState(int state);
+}
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9ec1122..a5f9822 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -107,15 +107,9 @@
}
/**
- * Blanks the display, if supported.
+ * Sets the display state, if supported.
*/
- public void blankLocked() {
- }
-
- /**
- * Unblanks the display, if supported.
- */
- public void unblankLocked() {
+ public void requestDisplayStateLocked(int state) {
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 75f1f53..a77443d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -176,6 +176,11 @@
public String address;
/**
+ * Display state.
+ */
+ public int state = Display.STATE_ON;
+
+ /**
* The UID of the application that owns this display, or zero if it is owned by the system.
* <p>
* If the display is private, then only the owner can use it.
@@ -219,6 +224,7 @@
&& rotation == other.rotation
&& type == other.type
&& Objects.equal(address, other.address)
+ && state == other.state
&& ownerUid == other.ownerUid
&& Objects.equal(ownerPackageName, other.ownerPackageName);
}
@@ -241,6 +247,7 @@
rotation = other.rotation;
type = other.type;
address = other.address;
+ state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
}
@@ -260,6 +267,7 @@
if (address != null) {
sb.append(", address ").append(address);
}
+ sb.append(", state ").append(Display.stateToString(state));
if (ownerUid != 0 || ownerPackageName != null) {
sb.append(", owner ").append(ownerPackageName);
sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 693f7d8..071417b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -121,10 +121,6 @@
private static final int MSG_REQUEST_TRAVERSAL = 4;
private static final int MSG_UPDATE_VIEWPORT = 5;
- private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
- private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
- private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
-
private final Context mContext;
private final DisplayManagerHandler mHandler;
private final Handler mUiHandler;
@@ -176,8 +172,9 @@
// Display power controller.
private DisplayPowerController mDisplayPowerController;
- // Set to true if all displays have been blanked by the power manager.
- private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN;
+ // The overall display state, independent of changes that might influence one
+ // display or another in particular.
+ private int mGlobalDisplayState = Display.STATE_UNKNOWN;
// Set to true when there are pending display changes that have yet to be applied
// to the surface flinger state.
@@ -315,21 +312,11 @@
}
}
- private void blankAllDisplaysFromPowerManagerInternal() {
+ private void requestGlobalDisplayStateInternal(int state) {
synchronized (mSyncRoot) {
- if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
- mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
- updateAllDisplayBlankingLocked();
- scheduleTraversalLocked(false);
- }
- }
- }
-
- private void unblankAllDisplaysFromPowerManagerInternal() {
- synchronized (mSyncRoot) {
- if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
- mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
- updateAllDisplayBlankingLocked();
+ if (mGlobalDisplayState != state) {
+ mGlobalDisplayState = state;
+ updateGlobalDisplayStateLocked();
scheduleTraversalLocked(false);
}
}
@@ -616,7 +603,7 @@
mDisplayDevices.add(device);
addLogicalDisplayLocked(device);
- updateDisplayBlankingLocked(device);
+ updateDisplayStateLocked(device);
scheduleTraversalLocked(false);
}
@@ -655,27 +642,20 @@
scheduleTraversalLocked(false);
}
- private void updateAllDisplayBlankingLocked() {
+ private void updateGlobalDisplayStateLocked() {
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
DisplayDevice device = mDisplayDevices.get(i);
- updateDisplayBlankingLocked(device);
+ updateDisplayStateLocked(device);
}
}
- private void updateDisplayBlankingLocked(DisplayDevice device) {
+ private void updateDisplayStateLocked(DisplayDevice device) {
// Blank or unblank the display immediately to match the state requested
- // by the power manager (if known).
+ // by the display power controller (if known).
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
- switch (mAllDisplayBlankStateFromPowerManager) {
- case DISPLAY_BLANK_STATE_BLANKED:
- device.blankLocked();
- break;
- case DISPLAY_BLANK_STATE_UNBLANKED:
- device.unblankLocked();
- break;
- }
+ device.requestDisplayStateLocked(mGlobalDisplayState);
}
}
@@ -816,9 +796,7 @@
+ device.getDisplayDeviceInfoLocked());
return;
}
- boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED)
- && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0;
- display.configureDisplayInTransactionLocked(device, isBlanked);
+ display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
// Update the viewports if needed.
if (!mDefaultViewport.valid
@@ -897,8 +875,7 @@
pw.println(" mOnlyCode=" + mOnlyCore);
pw.println(" mSafeMode=" + mSafeMode);
pw.println(" mPendingTraversal=" + mPendingTraversal);
- pw.println(" mAllDisplayBlankStateFromPowerManager="
- + mAllDisplayBlankStateFromPowerManager);
+ pw.println(" mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
pw.println(" mDefaultViewport=" + mDefaultViewport);
pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
@@ -1322,11 +1299,26 @@
private final class LocalService extends DisplayManagerInternal {
@Override
- public void initPowerManagement(DisplayPowerCallbacks callbacks, Handler handler,
+ public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
+ DisplayBlanker blanker = new DisplayBlanker() {
+ @Override
+ public void requestDisplayState(int state) {
+ // The order of operations is important for legacy reasons.
+ if (state == Display.STATE_OFF) {
+ requestGlobalDisplayStateInternal(state);
+ }
+
+ callbacks.onDisplayStateChange(state);
+
+ if (state != Display.STATE_OFF) {
+ requestGlobalDisplayStateInternal(state);
+ }
+ }
+ };
mDisplayPowerController = new DisplayPowerController(
- mContext, callbacks, handler, sensorManager);
+ mContext, callbacks, handler, sensorManager, blanker);
}
}
@@ -1343,16 +1335,6 @@
}
@Override
- public void blankAllDisplaysFromPowerManager() {
- blankAllDisplaysFromPowerManagerInternal();
- }
-
- @Override
- public void unblankAllDisplaysFromPowerManager() {
- unblankAllDisplaysFromPowerManagerInternal();
- }
-
- @Override
public DisplayInfo getDisplayInfo(int displayId) {
return getDisplayInfoInternal(displayId, Process.myUid());
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 62fb02a..1f38eb6 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -42,6 +42,7 @@
import android.util.Slog;
import android.util.Spline;
import android.util.TimeUtils;
+import android.view.Display;
import java.io.PrintWriter;
@@ -122,6 +123,9 @@
// The sensor manager.
private final SensorManager mSensorManager;
+ // The display blanker.
+ private final DisplayBlanker mBlanker;
+
// The proximity sensor, or null if not available or needed.
private Sensor mProximitySensor;
@@ -225,13 +229,15 @@
* Creates the display power controller.
*/
public DisplayPowerController(Context context,
- DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager) {
+ DisplayPowerCallbacks callbacks, Handler handler,
+ SensorManager sensorManager, DisplayBlanker blanker) {
mHandler = new DisplayControllerHandler(handler.getLooper());
mCallbacks = callbacks;
mBatteryStats = BatteryStatsService.getService();
mLights = LocalServices.getService(LightsManager.class);
mSensorManager = sensorManager;
+ mBlanker = blanker;
final Resources resources = context.getResources();
@@ -366,8 +372,11 @@
}
private void initialize() {
- mPowerState = new DisplayPowerState(new ElectronBeam(), mCallbacks,
- mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
+ // Initialize the power state object for the default display.
+ // In the future, we might manage multiple displays independently.
+ mPowerState = new DisplayPowerState(mBlanker,
+ mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
+ new ElectronBeam(Display.DEFAULT_DISPLAY));
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -384,7 +393,7 @@
// Initialize screen state for battery stats.
try {
- if (mPowerState.isScreenOn()) {
+ if (mPowerState.getScreenState() != Display.STATE_OFF) {
mBatteryStats.noteScreenOn();
} else {
mBatteryStats.noteScreenOff();
@@ -523,7 +532,7 @@
// Animate the screen on or off unless blocked.
if (mScreenOffBecauseOfProximity) {
// Screen off due to proximity.
- setScreenOn(false);
+ setScreenState(Display.STATE_OFF);
unblockScreenOn();
} else if (mPowerRequest.wantScreenOnAny()) {
// Want screen on.
@@ -534,7 +543,8 @@
// Turn the screen on. The contents of the screen may not yet
// be visible if the electron beam has not been dismissed because
// its last frame of animation is solid black.
- setScreenOn(true);
+ setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
+ ? Display.STATE_DOZING : Display.STATE_ON);
if (mPowerRequest.blockScreenOn
&& mPowerState.getElectronBeamLevel() == 0.0f) {
@@ -567,12 +577,12 @@
if (!mElectronBeamOnAnimator.isStarted()) {
if (!mElectronBeamOffAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 0.0f) {
- setScreenOn(false);
+ setScreenState(Display.STATE_OFF);
} else if (mPowerState.prepareElectronBeam(
mElectronBeamFadesConfig ?
ElectronBeam.MODE_FADE :
ElectronBeam.MODE_COOL_DOWN)
- && mPowerState.isScreenOn()) {
+ && mPowerState.getScreenState() != Display.STATE_OFF) {
mElectronBeamOffAnimator.start();
} else {
mElectronBeamOffAnimator.end();
@@ -610,9 +620,9 @@
private void blockScreenOn() {
if (!mScreenOnWasBlocked) {
mScreenOnWasBlocked = true;
+ mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
if (DEBUG) {
Slog.d(TAG, "Blocked screen on.");
- mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
}
}
}
@@ -627,11 +637,11 @@
}
}
- private void setScreenOn(boolean on) {
- if (mPowerState.isScreenOn() != on) {
- mPowerState.setScreenOn(on);
+ private void setScreenState(int state) {
+ if (mPowerState.getScreenState() != state) {
+ mPowerState.setScreenState(state);
try {
- if (on) {
+ if (state != Display.STATE_OFF) {
mBatteryStats.noteScreenOn();
} else {
mBatteryStats.noteScreenOff();
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index e1416d7..a5f8849 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -18,7 +18,6 @@
import com.android.server.lights.Light;
-import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
@@ -27,6 +26,7 @@
import android.util.IntProperty;
import android.util.Slog;
import android.view.Choreographer;
+import android.view.Display;
import java.io.PrintWriter;
@@ -54,12 +54,12 @@
private final Handler mHandler;
private final Choreographer mChoreographer;
- private final ElectronBeam mElectronBeam;
- private final DisplayPowerCallbacks mCallbacks;
+ private final DisplayBlanker mBlanker;
private final Light mBacklight;
+ private final ElectronBeam mElectronBeam;
private final PhotonicModulator mPhotonicModulator;
- private boolean mScreenOn;
+ private int mScreenState;
private int mScreenBrightness;
private boolean mScreenReady;
private boolean mScreenUpdatePending;
@@ -71,13 +71,12 @@
private Runnable mCleanListener;
- public DisplayPowerState(ElectronBeam electronBean,
- DisplayPowerCallbacks callbacks, Light backlight) {
+ public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
- mElectronBeam = electronBean;
- mCallbacks = callbacks;
+ mBlanker = blanker;
mBacklight = backlight;
+ mElectronBeam = electronBeam;
mPhotonicModulator = new PhotonicModulator();
// At boot time, we know that the screen is on and the electron beam
@@ -86,7 +85,7 @@
// Although we set the brightness to full on here, the display power controller
// will reset the brightness to a new level immediately before the changes
// actually have a chance to be applied.
- mScreenOn = true;
+ mScreenState = Display.STATE_ON;
mScreenBrightness = PowerManager.BRIGHTNESS_ON;
scheduleScreenUpdate();
@@ -122,25 +121,25 @@
};
/**
- * Sets whether the screen is on or off.
+ * Sets whether the screen is on, off, or dozing.
*/
- public void setScreenOn(boolean on) {
- if (mScreenOn != on) {
+ public void setScreenState(int state) {
+ if (mScreenState != state) {
if (DEBUG) {
- Slog.d(TAG, "setScreenOn: on=" + on);
+ Slog.d(TAG, "setScreenState: state=" + state);
}
- mScreenOn = on;
+ mScreenState = state;
mScreenReady = false;
scheduleScreenUpdate();
}
}
/**
- * Returns true if the screen is on.
+ * Gets the desired screen state.
*/
- public boolean isScreenOn() {
- return mScreenOn;
+ public int getScreenState() {
+ return mScreenState;
}
/**
@@ -155,7 +154,7 @@
}
mScreenBrightness = brightness;
- if (mScreenOn) {
+ if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate();
}
@@ -219,7 +218,7 @@
}
mElectronBeamLevel = level;
- if (mScreenOn) {
+ if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate(); // update backlight brightness
}
@@ -256,7 +255,7 @@
public void dump(PrintWriter pw) {
pw.println();
pw.println("Display Power State:");
- pw.println(" mScreenOn=" + mScreenOn);
+ pw.println(" mScreenState=" + Display.stateToString(mScreenState));
pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mScreenReady=" + mScreenReady);
pw.println(" mScreenUpdatePending=" + mScreenUpdatePending);
@@ -302,8 +301,9 @@
public void run() {
mScreenUpdatePending = false;
- int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
- if (mPhotonicModulator.setState(mScreenOn, brightness)) {
+ int brightness = mScreenState != Display.STATE_OFF
+ && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+ if (mPhotonicModulator.setState(mScreenState, brightness)) {
if (DEBUG) {
Slog.d(TAG, "Screen ready");
}
@@ -335,26 +335,26 @@
* Updates the state of the screen and backlight asynchronously on a separate thread.
*/
private final class PhotonicModulator {
- private static final boolean INITIAL_SCREEN_ON = false; // unknown, assume off
+ private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
private static final int INITIAL_BACKLIGHT = -1; // unknown
private final Object mLock = new Object();
- private boolean mPendingOn = INITIAL_SCREEN_ON;
+ private int mPendingState = INITIAL_SCREEN_STATE;
private int mPendingBacklight = INITIAL_BACKLIGHT;
- private boolean mActualOn = INITIAL_SCREEN_ON;
+ private int mActualState = INITIAL_SCREEN_STATE;
private int mActualBacklight = INITIAL_BACKLIGHT;
private boolean mChangeInProgress;
- public boolean setState(boolean on, int backlight) {
+ public boolean setState(int state, int backlight) {
synchronized (mLock) {
- if (on != mPendingOn || backlight != mPendingBacklight) {
+ if (state != mPendingState || backlight != mPendingBacklight) {
if (DEBUG) {
- Slog.d(TAG, "Requesting new screen state: on=" + on
- + ", backlight=" + backlight);
+ Slog.d(TAG, "Requesting new screen state: state="
+ + Display.stateToString(state) + ", backlight=" + backlight);
}
- mPendingOn = on;
+ mPendingState = state;
mPendingBacklight = backlight;
if (!mChangeInProgress) {
@@ -369,9 +369,9 @@
public void dump(PrintWriter pw) {
pw.println();
pw.println("Photonic Modulator State:");
- pw.println(" mPendingOn=" + mPendingOn);
+ pw.println(" mPendingState=" + Display.stateToString(mPendingState));
pw.println(" mPendingBacklight=" + mPendingBacklight);
- pw.println(" mActualOn=" + mActualOn);
+ pw.println(" mActualState=" + Display.stateToString(mActualState));
pw.println(" mActualBacklight=" + mActualBacklight);
pw.println(" mChangeInProgress=" + mChangeInProgress);
}
@@ -381,35 +381,35 @@
public void run() {
// Apply pending changes until done.
for (;;) {
- final boolean on;
- final boolean onChanged;
+ final int state;
+ final boolean stateChanged;
final int backlight;
final boolean backlightChanged;
synchronized (mLock) {
- on = mPendingOn;
- onChanged = (on != mActualOn);
+ state = mPendingState;
+ stateChanged = (state != mActualState);
backlight = mPendingBacklight;
backlightChanged = (backlight != mActualBacklight);
- if (!onChanged && !backlightChanged) {
+ if (!stateChanged && !backlightChanged) {
mChangeInProgress = false;
break;
}
- mActualOn = on;
+ mActualState = state;
mActualBacklight = backlight;
}
if (DEBUG) {
- Slog.d(TAG, "Updating screen state: on=" + on
- + ", backlight=" + backlight);
+ Slog.d(TAG, "Updating screen state: state="
+ + Display.stateToString(state) + ", backlight=" + backlight);
}
- if (onChanged && on) {
- mCallbacks.unblankAllDisplays();
+ if (stateChanged && state != Display.STATE_OFF) {
+ mBlanker.requestDisplayState(state);
}
if (backlightChanged) {
mBacklight.setBrightness(backlight);
}
- if (onChanged && !on) {
- mCallbacks.blankAllDisplays();
+ if (stateChanged && state == Display.STATE_OFF) {
+ mBlanker.requestDisplayState(state);
}
}
diff --git a/services/core/java/com/android/server/display/ElectronBeam.java b/services/core/java/com/android/server/display/ElectronBeam.java
index 13816bb..18e4049 100644
--- a/services/core/java/com/android/server/display/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ElectronBeam.java
@@ -35,7 +35,6 @@
import android.os.Looper;
import android.util.FloatMath;
import android.util.Slog;
-import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface.OutOfResourcesException;
import android.view.Surface;
@@ -74,6 +73,8 @@
// See code for details.
private static final int DEJANK_FRAMES = 3;
+ private final int mDisplayId;
+
// Set to true when the animation context has been fully prepared.
private boolean mPrepared;
private int mMode;
@@ -118,8 +119,8 @@
*/
public static final int MODE_FADE = 2;
-
- public ElectronBeam() {
+ public ElectronBeam(int displayId) {
+ mDisplayId = displayId;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
}
@@ -139,7 +140,7 @@
// Get the display size and layer stack.
// This is not expected to change while the electron beam surface is showing.
- DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
mDisplayLayerStack = displayInfo.layerStack;
mDisplayWidth = displayInfo.getNaturalWidth();
mDisplayHeight = displayInfo.getNaturalHeight();
@@ -528,7 +529,8 @@
mSurface = new Surface();
mSurface.copyFrom(mSurfaceControl);
- mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, mSurfaceControl);
+ mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+ mDisplayId, mSurfaceControl);
mSurfaceLayout.onDisplayTransaction();
} finally {
SurfaceControl.closeTransaction();
@@ -687,11 +689,13 @@
*/
private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
private final DisplayManagerInternal mDisplayManagerInternal;
+ private final int mDisplayId;
private SurfaceControl mSurfaceControl;
public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
- SurfaceControl surfaceControl) {
+ int displayId, SurfaceControl surfaceControl) {
mDisplayManagerInternal = displayManagerInternal;
+ mDisplayId = displayId;
mSurfaceControl = surfaceControl;
mDisplayManagerInternal.registerDisplayTransactionListener(this);
}
@@ -710,8 +714,7 @@
return;
}
- DisplayInfo displayInfo =
- mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
switch (displayInfo.rotation) {
case Surface.ROTATION_0:
mSurfaceControl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 02be477..2c8f1b4 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -101,7 +101,7 @@
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
- private boolean mBlanked;
+ private int mState = Display.STATE_UNKNOWN;
public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
SurfaceControl.PhysicalDisplayInfo phys) {
@@ -134,6 +134,7 @@
mInfo.width = mPhys.width;
mInfo.height = mPhys.height;
mInfo.refreshRate = mPhys.refreshRate;
+ mInfo.state = mState;
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
@@ -177,15 +178,16 @@
}
@Override
- public void blankLocked() {
- mBlanked = true;
- SurfaceControl.blankDisplay(getDisplayTokenLocked());
- }
-
- @Override
- public void unblankLocked() {
- mBlanked = false;
- SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+ public void requestDisplayStateLocked(int state) {
+ if (mState != state) {
+ if (state == Display.STATE_OFF && mState != Display.STATE_OFF) {
+ SurfaceControl.blankDisplay(getDisplayTokenLocked());
+ } else if (state != Display.STATE_OFF && mState == Display.STATE_OFF) {
+ SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+ }
+ mState = state;
+ updateDeviceInfoLocked();
+ }
}
@Override
@@ -193,7 +195,12 @@
super.dumpLocked(pw);
pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
pw.println("mPhys=" + mPhys);
- pw.println("mBlanked=" + mBlanked);
+ pw.println("mState=" + Display.stateToString(mState));
+ }
+
+ private void updateDeviceInfoLocked() {
+ mInfo = null;
+ sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index c26c438..d61a35b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -114,6 +114,7 @@
mInfo.copyFrom(mOverrideDisplayInfo);
mInfo.layerStack = mBaseDisplayInfo.layerStack;
mInfo.name = mBaseDisplayInfo.name;
+ mInfo.state = mBaseDisplayInfo.state;
} else {
mInfo.copyFrom(mBaseDisplayInfo);
}
@@ -212,6 +213,7 @@
mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
+ mBaseDisplayInfo.state = deviceInfo.state;
mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 007acf7..bfd8372c 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -194,12 +194,14 @@
private final int mDensityDpi;
private final boolean mSecure;
- private Surface mSurface;
+ private int mState;
private SurfaceTexture mSurfaceTexture;
+ private Surface mSurface;
private DisplayDeviceInfo mInfo;
public OverlayDisplayDevice(IBinder displayToken, String name,
- int width, int height, float refreshRate, int densityDpi, boolean secure,
+ int width, int height, float refreshRate,
+ int densityDpi, boolean secure, int state,
SurfaceTexture surfaceTexture) {
super(OverlayDisplayAdapter.this, displayToken);
mName = name;
@@ -208,6 +210,7 @@
mRefreshRate = refreshRate;
mDensityDpi = densityDpi;
mSecure = secure;
+ mState = state;
mSurfaceTexture = surfaceTexture;
}
@@ -230,6 +233,11 @@
}
}
+ public void setStateLocked(int state) {
+ mState = state;
+ mInfo = null;
+ }
+
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
@@ -247,6 +255,7 @@
}
mInfo.type = Display.TYPE_OVERLAY;
mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+ mInfo.state = mState;
}
return mInfo;
}
@@ -288,11 +297,12 @@
// Called on the UI thread.
@Override
- public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
+ public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, int state) {
synchronized (getSyncRoot()) {
IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
mDevice = new OverlayDisplayDevice(displayToken, mName,
- mWidth, mHeight, refreshRate, mDensityDpi, mSecure, surfaceTexture);
+ mWidth, mHeight, refreshRate, mDensityDpi, mSecure,
+ state, surfaceTexture);
sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
}
@@ -309,6 +319,17 @@
}
}
+ // Called on the UI thread.
+ @Override
+ public void onStateChanged(int state) {
+ synchronized (getSyncRoot()) {
+ if (mDevice != null) {
+ mDevice.setStateLocked(state);
+ sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ }
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println(" " + mName + ":");
pw.println(" mWidth=" + mWidth);
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index f1dd60a..06891f3 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -282,6 +282,7 @@
if (displayId == mDefaultDisplay.getDisplayId()) {
if (updateDefaultDisplayInfo()) {
relayout();
+ mListener.onStateChanged(mDefaultDisplayInfo.state);
} else {
dismiss();
}
@@ -301,7 +302,8 @@
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
int width, int height) {
- mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate);
+ mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate,
+ mDefaultDisplayInfo.state);
}
@Override
@@ -370,7 +372,9 @@
* Watches for significant changes in the overlay display window lifecycle.
*/
public interface Listener {
- public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate);
+ public void onWindowCreated(SurfaceTexture surfaceTexture,
+ float refreshRate, int state);
public void onWindowDestroyed();
+ public void onStateChanged(int state);
}
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
index 64b51c9..baae1d9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
@@ -182,11 +182,49 @@
}
/**
+ * Send <Active Source> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendActiveSource(int physicalAddress) {
+ logWarning("<Active Source> not valid for the device type: " + mType
+ + " address:" + physicalAddress);
+ }
+
+ /**
+ * Send <Inactive Source> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendInactiveSource(int physicalAddress) {
+ logWarning("<Inactive Source> not valid for the device type: " + mType
+ + " address:" + physicalAddress);
+ }
+
+ /**
+ * Send <Image View On> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendImageViewOn() {
+ logWarning("<Image View On> not valid for the device type: " + mType);
+ }
+
+ /**
+ * Send <Text View On> command. The default implementation does nothing. Should be
+ * overriden by subclass.
+ */
+ public void sendTextViewOn() {
+ logWarning("<Text View On> not valid for the device type: " + mType);
+ }
+
+ /**
* Check if the connected sink device is in powered-on state. The default implementation
* simply returns false. Should be overriden by subclass to report the correct state.
*/
public boolean isSinkDeviceOn() {
- Log.w(TAG, "Not valid for the device type: " + mType);
+ logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
return false;
}
+
+ private void logWarning(String msg) {
+ Log.w(TAG, msg);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
index 0310264..f8cf11d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
@@ -66,14 +66,11 @@
// 1) Response for the queried power status request arrives. Update the status.
// 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
// into standby mode too.
- // 3) Broadcast <Report Physical Address> command from TV, which is sent while it boots up.
if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
mSinkDevicePowerStatus = params[0];
} else if (srcAddress == HdmiCec.ADDR_TV) {
if (opcode == HdmiCec.MESSAGE_STANDBY) {
mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
- } else if (opcode == HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS) {
- mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_ON;
}
}
super.handleMessage(srcAddress, dstAddress, opcode, params);
@@ -95,4 +92,38 @@
public boolean isSinkDeviceOn() {
return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
}
+
+ @Override
+ public void sendActiveSource(int physicalAddress) {
+ setIsActiveSource(true);
+ byte[] param = new byte[] {
+ (byte) ((physicalAddress >> 8) & 0xff),
+ (byte) (physicalAddress & 0xff)
+ };
+ getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
+ param);
+ }
+
+ @Override
+ public void sendInactiveSource(int physicalAddress) {
+ setIsActiveSource(false);
+ byte[] param = new byte[] {
+ (byte) ((physicalAddress >> 8) & 0xff),
+ (byte) (physicalAddress & 0xff)
+ };
+ getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE,
+ param);
+ }
+
+ @Override
+ public void sendImageViewOn() {
+ getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON,
+ HdmiCecService.EMPTY_PARAM);
+ }
+
+ @Override
+ public void sendTextViewOn() {
+ getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON,
+ HdmiCecService.EMPTY_PARAM);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
index aa496c5..0a4c719 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java
@@ -277,14 +277,7 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.setIsActiveSource(true);
- int physicalAddress = nativeGetPhysicalAddress(mNativePtr);
- byte[] param = new byte[] {
- (byte) ((physicalAddress >> 8) & 0xff),
- (byte) (physicalAddress & 0xff)
- };
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
- HdmiCec.MESSAGE_ACTIVE_SOURCE, param);
+ device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr));
}
}
@@ -293,9 +286,7 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.setIsActiveSource(false);
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
- HdmiCec.MESSAGE_INACTIVE_SOURCE, EMPTY_PARAM);
+ device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr));
}
}
@@ -304,8 +295,7 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
- HdmiCec.MESSAGE_IMAGE_VIEW_ON, EMPTY_PARAM);
+ device.sendImageViewOn();
}
}
@@ -314,8 +304,16 @@
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
- HdmiCec.MESSAGE_TEXT_VIEW_ON, EMPTY_PARAM);
+ device.sendTextViewOn();
+ }
+ }
+
+ public void sendGiveDevicePowerStatus(IBinder b, int address) {
+ enforceAccessPermission();
+ synchronized (mLock) {
+ HdmiCecDevice device = getLogicalDeviceLocked(b);
+ nativeSendMessage(mNativePtr, device.getType(), address,
+ HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 316bd57..54cb035 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -185,6 +185,7 @@
InputChannel fromChannel, InputChannel toChannel);
private static native void nativeSetPointerSpeed(long ptr, int speed);
private static native void nativeSetShowTouches(long ptr, boolean enabled);
+ private static native void nativeSetInteractive(long ptr, boolean interactive);
private static native void nativeReloadCalibration(long ptr);
private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
int repeat, int token);
@@ -1404,14 +1405,13 @@
}
// Native callback.
- private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
- return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
- event, policyFlags, isScreenOn);
+ private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+ return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
// Native callback.
- private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
- return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+ private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+ return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing(
whenNanos, policyFlags);
}
@@ -1570,9 +1570,9 @@
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason);
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);
@@ -1740,5 +1740,10 @@
public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
return injectInputEventInternal(event, displayId, mode);
}
+
+ @Override
+ public void setInteractive(boolean interactive) {
+ nativeSetInteractive(mPtr, interactive);
+ }
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index eb7cc4c..855ae23 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1730,7 +1730,7 @@
private void updateScreenOn() {
synchronized (mRulesLock) {
try {
- mScreenOn = mPowerManager.isScreenOn();
+ mScreenOn = mPowerManager.isInteractive();
} catch (RemoteException e) {
// ignored; service lives in system_server
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index f72efff..d84e8e1 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -28,6 +28,7 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.hardware.input.InputManagerInternal;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
@@ -86,6 +87,7 @@
private final ScreenOnBlocker mScreenOnBlocker;
private final WindowManagerPolicy mPolicy;
private final ActivityManagerInternal mActivityManagerInternal;
+ private final InputManagerInternal mInputManagerInternal;
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
@@ -121,6 +123,7 @@
mScreenOnBlocker = screenOnBlocker;
mPolicy = policy;
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mHandler = new NotifierHandler(looper);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -232,73 +235,58 @@
}
/**
- * Called when the device is waking up from sleep and the
- * display is about to be turned on.
+ * Notifies that the device is changing interactive state.
*/
- public void onWakeUpStarted() {
+ public void onInteractiveStateChangeStarted(boolean interactive, int reason) {
if (DEBUG) {
- Slog.d(TAG, "onWakeUpStarted");
+ Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
+ + ", reason=" + reason);
}
synchronized (mLock) {
- if (mActualPowerState != POWER_STATE_AWAKE) {
- mActualPowerState = POWER_STATE_AWAKE;
- mPendingWakeUpBroadcast = true;
- if (!mScreenOnBlockerAcquired) {
- mScreenOnBlockerAcquired = true;
- mScreenOnBlocker.acquire();
+ if (interactive) {
+ // Waking up...
+ if (mActualPowerState != POWER_STATE_AWAKE) {
+ mActualPowerState = POWER_STATE_AWAKE;
+ mPendingWakeUpBroadcast = true;
+ if (!mScreenOnBlockerAcquired) {
+ mScreenOnBlockerAcquired = true;
+ mScreenOnBlocker.acquire();
+ }
+ updatePendingBroadcastLocked();
}
- updatePendingBroadcastLocked();
+ } else {
+ // Going to sleep...
+ mLastGoToSleepReason = reason;
}
+ mInputManagerInternal.setInteractive(interactive);
}
}
/**
- * Called when the device has finished waking up from sleep
- * and the display has been turned on.
+ * Notifies that the device has finished changing interactive state.
*/
- public void onWakeUpFinished() {
+ public void onInteractiveStateChangeFinished(boolean interactive) {
if (DEBUG) {
- Slog.d(TAG, "onWakeUpFinished");
- }
- }
-
- /**
- * Called when the device is going to sleep.
- */
- public void onGoToSleepStarted(int reason) {
- if (DEBUG) {
- Slog.d(TAG, "onGoToSleepStarted");
+ Slog.d(TAG, "onInteractiveChangeFinished");
}
synchronized (mLock) {
- mLastGoToSleepReason = reason;
- }
- }
-
- /**
- * Called when the device has finished going to sleep and the
- * display has been turned off.
- *
- * This is a good time to make transitions that we don't want the user to see,
- * such as bringing the key guard to focus. There's no guarantee for this,
- * however because the user could turn the device on again at any time.
- * Some things may need to be protected by other mechanisms that defer screen on.
- */
- public void onGoToSleepFinished() {
- if (DEBUG) {
- Slog.d(TAG, "onGoToSleepFinished");
- }
-
- synchronized (mLock) {
- if (mActualPowerState != POWER_STATE_ASLEEP) {
- mActualPowerState = POWER_STATE_ASLEEP;
- mPendingGoToSleepBroadcast = true;
- if (mUserActivityPending) {
- mUserActivityPending = false;
- mHandler.removeMessages(MSG_USER_ACTIVITY);
+ if (!interactive) {
+ // Finished going to sleep...
+ // This is a good time to make transitions that we don't want the user to see,
+ // such as bringing the key guard to focus. There's no guarantee for this,
+ // however because the user could turn the device on again at any time.
+ // Some things may need to be protected by other mechanisms that defer screen on.
+ if (mActualPowerState != POWER_STATE_ASLEEP) {
+ mActualPowerState = POWER_STATE_ASLEEP;
+ mPendingGoToSleepBroadcast = true;
+ if (mUserActivityPending) {
+ mUserActivityPending = false;
+ mHandler.removeMessages(MSG_USER_ACTIVITY);
+ }
+ updatePendingBroadcastLocked();
}
- updatePendingBroadcastLocked();
}
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 90363d7..82cef7f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -62,6 +62,7 @@
import android.util.Log;
import android.util.Slog;
import android.util.TimeUtils;
+import android.view.Display;
import android.view.WindowManagerPolicy;
import java.io.FileDescriptor;
@@ -209,6 +210,10 @@
// A bitfield that summarizes the state of all active wakelocks.
private int mWakeLockSummary;
+ // True if the device is in an interactive state.
+ private boolean mInteractive;
+ private boolean mInteractiveChanging;
+
// If true, instructs the display controller to wait for the proximity sensor to
// go negative before turning the screen on.
private boolean mRequestWaitForNegativeProximity;
@@ -217,11 +222,6 @@
private long mLastWakeTime;
private long mLastSleepTime;
- // True if we need to send a wake up or go to sleep finished notification
- // when the display is ready.
- private boolean mSendWakeUpFinishedNotificationWhenReady;
- private boolean mSendGoToSleepFinishedNotificationWhenReady;
-
// Timestamp of the last call to user activity.
private long mLastUserActivityTime;
private long mLastUserActivityTimeNoChangeLights;
@@ -265,11 +265,11 @@
// True if auto-suspend mode is enabled.
// Refer to autosuspend.h.
- private boolean mAutoSuspendModeEnabled;
+ private boolean mHalAutoSuspendModeEnabled;
// True if interactive mode is enabled.
// Refer to power.h.
- private boolean mInteractiveModeEnabled;
+ private boolean mHalInteractiveModeEnabled;
// True if the device is plugged into a power source.
private boolean mIsPowered;
@@ -289,10 +289,10 @@
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
// True to decouple auto-suspend mode from the display state.
- private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+ private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig;
// True to decouple interactive mode from the display state.
- private boolean mDecoupleInteractiveModeFromDisplayConfig;
+ private boolean mDecoupleHalInteractiveModeFromDisplayConfig;
// True if the device should wake up when plugged or unplugged.
private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
@@ -397,7 +397,6 @@
private native void nativeInit();
- private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
private static native void nativeAcquireSuspendBlocker(String name);
private static native void nativeReleaseSuspendBlocker(String name);
private static native void nativeSetInteractive(boolean enable);
@@ -412,13 +411,17 @@
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
+ mHalAutoSuspendModeEnabled = false;
+ mHalInteractiveModeEnabled = true;
mScreenOnBlocker = new ScreenOnBlockerImpl();
mWakefulness = WAKEFULNESS_AWAKE;
- }
+ mInteractive = true;
- nativeInit();
- nativeSetPowerState(true, true);
+ nativeInit();
+ nativeSetAutoSuspend(false);
+ nativeSetInteractive(true);
+ }
}
@Override
@@ -446,14 +449,6 @@
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
-
- // Forcibly turn the screen on at boot so that it is in a known power state.
- // We do this in init() rather than in the constructor because setting the
- // screen state requires a call into surface flinger which then needs to call back
- // into the activity manager to check permissions. Unfortunately the
- // activity manager is not running when the constructor is called, so we
- // have to defer setting the screen state until this point.
- mDisplayPowerCallbacks.unblankAllDisplays();
}
void setPolicy(WindowManagerPolicy policy) {
@@ -547,9 +542,9 @@
private void readConfigurationLocked() {
final Resources resources = mContext.getResources();
- mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+ mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
- mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+ mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
@@ -867,11 +862,6 @@
return false;
}
- // Called from native code.
- private void wakeUpFromNative(long eventTime) {
- wakeUpInternal(eventTime);
- }
-
private void wakeUpInternal(long eventTime) {
synchronized (mLock) {
if (wakeUpNoUpdateLocked(eventTime)) {
@@ -902,26 +892,16 @@
break;
}
- if (mWakefulness != WAKEFULNESS_DREAMING) {
- sendPendingNotificationsLocked();
- mNotifier.onWakeUpStarted();
- mSendWakeUpFinishedNotificationWhenReady = true;
- }
-
mLastWakeTime = eventTime;
- mWakefulness = WAKEFULNESS_AWAKE;
mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_AWAKE;
+ setInteractiveStateLocked(true, 0);
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
return true;
}
- // Called from native code.
- private void goToSleepFromNative(long eventTime, int reason) {
- goToSleepInternal(eventTime, reason);
- }
-
private void goToSleepInternal(long eventTime, int reason) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason)) {
@@ -958,14 +938,11 @@
break;
}
- sendPendingNotificationsLocked();
- mNotifier.onGoToSleepStarted(reason);
- mSendGoToSleepFinishedNotificationWhenReady = true;
-
mLastSleepTime = eventTime;
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_DOZING;
mSandmanSummoned = true;
+ setInteractiveStateLocked(false, reason);
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
@@ -1007,6 +984,7 @@
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_DREAMING;
mSandmanSummoned = true;
+ setInteractiveStateLocked(true, 0);
return true;
}
@@ -1025,9 +1003,27 @@
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_ASLEEP;
+ setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
return true;
}
+ private void setInteractiveStateLocked(boolean interactive, int reason) {
+ if (mInteractive != interactive) {
+ finishInteractiveStateChangeLocked();
+
+ mInteractive = interactive;
+ mInteractiveChanging = true;
+ mNotifier.onInteractiveStateChangeStarted(interactive, reason);
+ }
+ }
+
+ private void finishInteractiveStateChangeLocked() {
+ if (mInteractiveChanging) {
+ mNotifier.onInteractiveStateChangeFinished(mInteractive);
+ mInteractiveChanging = false;
+ }
+ }
+
/**
* Updates the global power state based on dirty bits recorded in mDirty.
*
@@ -1071,7 +1067,7 @@
// Phase 3: Send notifications, if needed.
if (mDisplayReady) {
- sendPendingNotificationsLocked();
+ finishInteractiveStateChangeLocked();
}
// Phase 4: Update suspend blocker.
@@ -1080,17 +1076,6 @@
updateSuspendBlockerLocked();
}
- private void sendPendingNotificationsLocked() {
- if (mSendWakeUpFinishedNotificationWhenReady) {
- mSendWakeUpFinishedNotificationWhenReady = false;
- mNotifier.onWakeUpFinished();
- }
- if (mSendGoToSleepFinishedNotificationWhenReady) {
- mSendGoToSleepFinishedNotificationWhenReady = false;
- mNotifier.onGoToSleepFinished();
- }
- }
-
/**
* Updates the value of mIsPowered.
* Sets DIRTY_IS_POWERED if a change occurred.
@@ -1210,48 +1195,45 @@
mWakeLockSummary |= WAKE_LOCK_CPU;
break;
case PowerManager.FULL_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
- mWakeLockSummary |= WAKE_LOCK_CPU
- | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
- }
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
- mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
- }
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
- mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
- }
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING
- || mWakefulness == WAKEFULNESS_DOZING) {
- mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
- }
+ mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
break;
case PowerManager.DOZE_WAKE_LOCK:
- if (mWakefulness == WAKEFULNESS_DOZING) {
- mWakeLockSummary |= WAKE_LOCK_DOZE;
- }
+ mWakeLockSummary |= WAKE_LOCK_DOZE;
break;
}
}
+ // Cancel wake locks that make no sense based on the current state.
+ if (mWakefulness != WAKEFULNESS_DOZING) {
+ mWakeLockSummary &= ~WAKE_LOCK_DOZE;
+ }
+ if (mWakefulness == WAKEFULNESS_ASLEEP
+ || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+ mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
+ | WAKE_LOCK_BUTTON_BRIGHT);
+ if (mWakefulness == WAKEFULNESS_ASLEEP) {
+ mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+ }
+ }
+
+ // Infer implied wake locks where necessary based on the current state.
+ if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
+ } else if (mWakefulness == WAKEFULNESS_DREAMING) {
+ mWakeLockSummary |= WAKE_LOCK_CPU;
+ }
+ }
+
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
+ wakefulnessToString(mWakefulness)
@@ -1269,12 +1251,14 @@
*/
private void updateUserActivitySummaryLocked(long now, int dirty) {
// Update the status of the user activity timeout timer.
- if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
+ if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
+ | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING) {
+ || mWakefulness == WAKEFULNESS_DREAMING
+ || mWakefulness == WAKEFULNESS_DOZING) {
final int screenOffTimeout = getScreenOffTimeoutLocked();
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
@@ -1598,8 +1582,6 @@
| DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
final int newScreenState = getDesiredScreenPowerStateLocked();
mDisplayPowerRequest.screenState = newScreenState;
- nativeSetPowerState(isScreenOnLocked(),
- newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
int screenBrightness = mScreenBrightnessSettingDefault;
float screenAutoBrightnessAdjustment = 0.0f;
@@ -1681,7 +1663,7 @@
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
new DisplayManagerInternal.DisplayPowerCallbacks() {
- private boolean mBlanked;
+ private int mDisplayState = Display.STATE_UNKNOWN;
@Override
public void onStateChanged() {
@@ -1712,6 +1694,33 @@
}
@Override
+ public void onDisplayStateChange(int state) {
+ // This method is only needed to support legacy display blanking behavior
+ // where the display's power state is coupled to suspend or to the power HAL.
+ // The order of operations matters here.
+ synchronized (mLock) {
+ if (mDisplayState != state) {
+ mDisplayState = state;
+ if (state == Display.STATE_OFF) {
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(false);
+ }
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(true);
+ }
+ } else {
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(true);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
public void acquireSuspendBlocker() {
mDisplaySuspendBlocker.acquire();
}
@@ -1722,37 +1731,9 @@
}
@Override
- public void blankAllDisplays() {
- synchronized (this) {
- mBlanked = true;
- mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
- if (!mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(false);
- }
- if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(true);
- }
- }
- }
-
- @Override
- public void unblankAllDisplays() {
- synchronized (this) {
- if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(false);
- }
- if (!mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(true);
- }
- mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
- mBlanked = false;
- }
- }
-
- @Override
public String toString() {
synchronized (this) {
- return "blanked=" + mBlanked;
+ return "state=" + Display.stateToString(mDisplayState);
}
}
};
@@ -1773,11 +1754,11 @@
// Disable auto-suspend if needed.
if (!autoSuspend) {
- if (mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(false);
+ if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(false);
}
- if (mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(true);
+ if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(true);
}
}
@@ -1803,11 +1784,11 @@
// Enable auto-suspend if needed.
if (autoSuspend) {
- if (mDecoupleInteractiveModeFromDisplayConfig) {
- setInteractiveModeLocked(false);
+ if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(false);
}
- if (mDecoupleAutoSuspendModeFromDisplayConfig) {
- setAutoSuspendModeLocked(true);
+ if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(true);
}
}
}
@@ -1834,42 +1815,32 @@
return false;
}
- private void setAutoSuspendModeLocked(boolean enable) {
- if (enable != mAutoSuspendModeEnabled) {
+ private void setHalAutoSuspendModeLocked(boolean enable) {
+ if (enable != mHalAutoSuspendModeEnabled) {
if (DEBUG) {
- Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+ Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
}
- mAutoSuspendModeEnabled = enable;
+ mHalAutoSuspendModeEnabled = enable;
nativeSetAutoSuspend(enable);
}
}
- private void setInteractiveModeLocked(boolean enable) {
- if (enable != mInteractiveModeEnabled) {
+ private void setHalInteractiveModeLocked(boolean enable) {
+ if (enable != mHalInteractiveModeEnabled) {
if (DEBUG) {
- Slog.d(TAG, "Setting interactive mode to " + enable);
+ Slog.d(TAG, "Setting HAL interactive mode to " + enable);
}
- mInteractiveModeEnabled = enable;
+ mHalInteractiveModeEnabled = enable;
nativeSetInteractive(enable);
}
}
- private boolean isScreenOnInternal() {
+ private boolean isInteractiveInternal() {
synchronized (mLock) {
- // XXX This is a temporary hack to let certain parts of the system pretend the
- // screen is still on even when dozing and we would normally want to report
- // screen off. Will be removed when the window manager is modified to use
- // the true blanking state of the display.
- return isScreenOnLocked()
- || mWakefulness == WAKEFULNESS_DOZING;
+ return mInteractive;
}
}
- private boolean isScreenOnLocked() {
- return mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING;
- }
-
private void handleBatteryStateChangedLocked() {
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();
@@ -2090,6 +2061,7 @@
pw.println("Power Manager State:");
pw.println(" mDirty=0x" + Integer.toHexString(mDirty));
pw.println(" mWakefulness=" + wakefulnessToString(mWakefulness));
+ pw.println(" mInteractive=" + mInteractive);
pw.println(" mIsPowered=" + mIsPowered);
pw.println(" mPlugType=" + mPlugType);
pw.println(" mBatteryLevel=" + mBatteryLevel);
@@ -2099,8 +2071,8 @@
pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
- pw.println(" mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
- pw.println(" mInteactiveModeEnabled=" + mInteractiveModeEnabled);
+ pw.println(" mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
+ pw.println(" mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
@@ -2108,10 +2080,6 @@
pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
- pw.println(" mSendWakeUpFinishedNotificationWhenReady="
- + mSendWakeUpFinishedNotificationWhenReady);
- pw.println(" mSendGoToSleepFinishedNotificationWhenReady="
- + mSendGoToSleepFinishedNotificationWhenReady);
pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
pw.println(" mLastUserActivityTimeNoChangeLights="
+ TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
@@ -2121,10 +2089,10 @@
pw.println();
pw.println("Settings and Configuration:");
- pw.println(" mDecoupleAutoSuspendModeFromDisplayConfig="
- + mDecoupleAutoSuspendModeFromDisplayConfig);
- pw.println(" mDecoupleInteractiveModeFromDisplayConfig="
- + mDecoupleInteractiveModeFromDisplayConfig);
+ pw.println(" mDecoupleHalAutoSuspendModeFromDisplayConfig="
+ + mDecoupleHalAutoSuspendModeFromDisplayConfig);
+ pw.println(" mDecoupleHalInteractiveModeFromDisplayConfig="
+ + mDecoupleHalInteractiveModeFromDisplayConfig);
pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig="
+ mWakeUpWhenPluggedOrUnpluggedConfig);
pw.println(" mSuspendWhenScreenOffDueToProximityConfig="
@@ -2725,10 +2693,10 @@
}
@Override // Binder call
- public boolean isScreenOn() {
+ public boolean isInteractive() {
final long ident = Binder.clearCallingIdentity();
try {
- return isScreenOnInternal();
+ return isInteractiveInternal();
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4aae5c1..b27c8d6 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -355,17 +355,16 @@
/* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */
@Override
- public int interceptKeyBeforeQueueing(
- KeyEvent event, int policyFlags, boolean isScreenOn) {
- return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+ return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}
/* Provides an opportunity for the window manager policy to intercept early
* motion event processing when the screen is off since these events are normally
* dropped. */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
- return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags);
+ public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+ return mService.mPolicy.interceptWakeMotionBeforeQueueing(whenNanos, policyFlags);
}
/* Provides an opportunity for the window manager policy to process a key before
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index a00aaa8..54c9755 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -204,6 +204,11 @@
} else {
ALOGV("Logical Address Allocation success: %d", addr);
mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
+
+ // Broadcast <Report Physical Address> when a new logical address was allocated to let
+ // other devices discover the new logical device and its logical - physical address
+ // association.
+ sendReportPhysicalAddress();
}
return addr;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index b3247ff..4085991 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -71,7 +71,7 @@
jmethodID notifyANR;
jmethodID filterInputEvent;
jmethodID interceptKeyBeforeQueueing;
- jmethodID interceptMotionBeforeQueueingWhenScreenOff;
+ jmethodID interceptWakeMotionBeforeQueueing;
jmethodID interceptKeyBeforeDispatching;
jmethodID dispatchUnhandledKey;
jmethodID checkInjectEventsPermission;
@@ -189,6 +189,7 @@
void setSystemUiVisibility(int32_t visibility);
void setPointerSpeed(int32_t speed);
void setShowTouches(bool enabled);
+ void setInteractive(bool interactive);
void reloadCalibration();
/* --- InputReaderPolicyInterface implementation --- */
@@ -214,7 +215,6 @@
virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
- virtual bool isKeyRepeatEnabled();
virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
virtual nsecs_t interceptKeyBeforeDispatching(
@@ -262,14 +262,12 @@
wp<PointerController> pointerController;
} mLocked;
+ volatile bool mInteractive;
+
void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
void ensureSpriteControllerLocked();
- // Power manager interactions.
- bool isScreenOn();
- bool isScreenBright();
-
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
static inline JNIEnv* jniEnv() {
@@ -281,7 +279,7 @@
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
- mLooper(looper) {
+ mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
@@ -637,11 +635,6 @@
}
}
-bool NativeInputManager::isKeyRepeatEnabled() {
- // Only enable automatic key repeating when the screen is on.
- return isScreenOn();
-}
-
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
Vector<sp<InputWindowHandle> > windowHandles;
@@ -753,19 +746,15 @@
InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
}
+void NativeInputManager::setInteractive(bool interactive) {
+ mInteractive = interactive;
+}
+
void NativeInputManager::reloadCalibration() {
mInputManager->getReader()->requestRefreshConfiguration(
InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION);
}
-bool NativeInputManager::isScreenOn() {
- return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
- return android_server_PowerManagerService_isScreenBright();
-}
-
TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
JNIEnv *env, jfloatArray matrixArr) {
ScopedFloatArrayRO matrix(env, matrixArr);
@@ -841,18 +830,18 @@
// - Ignore untrusted events and pass them along.
// - Ask the window manager what to do with normal events and trusted injected events.
// - For normal events wake and brighten the screen if currently off or dim.
+ if (mInteractive) {
+ policyFlags |= POLICY_FLAG_INTERACTIVE;
+ }
if ((policyFlags & POLICY_FLAG_TRUSTED)) {
nsecs_t when = keyEvent->getEventTime();
- bool isScreenOn = this->isScreenOn();
- bool isScreenBright = this->isScreenBright();
-
JNIEnv* env = jniEnv();
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
jint wmActions;
if (keyEventObj) {
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
- keyEventObj, policyFlags, isScreenOn);
+ keyEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
@@ -863,16 +852,6 @@
wmActions = 0;
}
- if (!(policyFlags & POLICY_FLAG_INJECTED)) {
- if (!isScreenOn) {
- policyFlags |= POLICY_FLAG_WOKE_HERE;
- }
-
- if (!isScreenBright) {
- policyFlags |= POLICY_FLAG_BRIGHT_HERE;
- }
- }
-
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
} else {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
@@ -885,24 +864,22 @@
// - No special filtering for injected events required at this time.
// - Filter normal events based on screen state.
// - For normal events brighten (but do not wake) the screen if currently dim.
+ if (mInteractive) {
+ policyFlags |= POLICY_FLAG_INTERACTIVE;
+ }
if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
- if (isScreenOn()) {
+ if (policyFlags & POLICY_FLAG_INTERACTIVE) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
-
- if (!isScreenBright()) {
- policyFlags |= POLICY_FLAG_BRIGHT_HERE;
- }
- } else {
+ } else if (policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED)) {
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
- gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
+ gServiceClassInfo.interceptWakeMotionBeforeQueueing,
when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
- "interceptMotionBeforeQueueingWhenScreenOff")) {
+ "interceptWakeMotionBeforeQueueing")) {
wmActions = 0;
}
- policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
} else {
@@ -1285,6 +1262,13 @@
im->setShowTouches(enabled);
}
+static void nativeSetInteractive(JNIEnv* env,
+ jclass clazz, jlong ptr, jboolean interactive) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->setInteractive(interactive);
+}
+
static void nativeReloadCalibration(JNIEnv* env, jclass clazz, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
im->reloadCalibration();
@@ -1395,6 +1379,8 @@
(void*) nativeSetPointerSpeed },
{ "nativeSetShowTouches", "(JZ)V",
(void*) nativeSetShowTouches },
+ { "nativeSetInteractive", "(JZ)V",
+ (void*) nativeSetInteractive },
{ "nativeReloadCalibration", "(J)V",
(void*) nativeReloadCalibration },
{ "nativeVibrate", "(JI[JII)V",
@@ -1453,11 +1439,10 @@
"filterInputEvent", "(Landroid/view/InputEvent;I)Z");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
- "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
+ "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
- GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
- clazz,
- "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
+ GET_METHOD_ID(gServiceClassInfo.interceptWakeMotionBeforeQueueing, clazz,
+ "interceptWakeMotionBeforeQueueing", "(JI)I");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
"interceptKeyBeforeDispatching",
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index dbf5439..33e0bd7 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -42,8 +42,6 @@
// ----------------------------------------------------------------------------
static struct {
- jmethodID wakeUpFromNative;
- jmethodID goToSleepFromNative;
jmethodID userActivityFromNative;
} gPowerManagerServiceClassInfo;
@@ -52,10 +50,6 @@
static jobject gPowerManagerServiceObj;
static struct power_module* gPowerModule;
-static Mutex gPowerManagerLock;
-static bool gScreenOn;
-static bool gScreenBright;
-
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
// Throttling interval for user activity calls.
@@ -73,16 +67,6 @@
return false;
}
-bool android_server_PowerManagerService_isScreenOn() {
- AutoMutex _l(gPowerManagerLock);
- return gScreenOn;
-}
-
-bool android_server_PowerManagerService_isScreenBright() {
- AutoMutex _l(gPowerManagerLock);
- return gScreenBright;
-}
-
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
// Tell the power HAL when user activity occurs.
if (gPowerModule && gPowerModule->powerHint) {
@@ -114,28 +98,6 @@
}
}
-void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
- if (gPowerManagerServiceObj) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
-
- env->CallVoidMethod(gPowerManagerServiceObj,
- gPowerManagerServiceClassInfo.wakeUpFromNative,
- nanoseconds_to_milliseconds(eventTime));
- checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
- }
-}
-
-void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
- if (gPowerManagerServiceObj) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
-
- env->CallVoidMethod(gPowerManagerServiceObj,
- gPowerManagerServiceClassInfo.goToSleepFromNative,
- nanoseconds_to_milliseconds(eventTime), 0);
- checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
- }
-}
-
// ----------------------------------------------------------------------------
static void nativeInit(JNIEnv* env, jobject obj) {
@@ -150,13 +112,6 @@
}
}
-static void nativeSetPowerState(JNIEnv* env,
- jclass clazz, jboolean screenOn, jboolean screenBright) {
- AutoMutex _l(gPowerManagerLock);
- gScreenOn = screenOn;
- gScreenBright = screenBright;
-}
-
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
@@ -207,8 +162,6 @@
/* name, signature, funcPtr */
{ "nativeInit", "()V",
(void*) nativeInit },
- { "nativeSetPowerState", "(ZZ)V",
- (void*) nativeSetPowerState },
{ "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeAcquireSuspendBlocker },
{ "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
@@ -243,12 +196,6 @@
jclass clazz;
FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
- GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
- "wakeUpFromNative", "(J)V");
-
- GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
- "goToSleepFromNative", "(JI)V");
-
GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
"userActivityFromNative", "(JII)V");
@@ -256,8 +203,6 @@
for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
gLastEventTime[i] = LLONG_MIN;
}
- gScreenOn = true;
- gScreenBright = true;
gPowerManagerServiceObj = NULL;
gPowerModule = NULL;
return 0;
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
index b48e546..f5fd3d6 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -24,11 +24,7 @@
namespace android {
-extern bool android_server_PowerManagerService_isScreenOn();
-extern bool android_server_PowerManagerService_isScreenBright();
extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
-extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
-extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
} // namespace android
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 983ca2d..35f9314 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2888,6 +2888,32 @@
}
@Override
+ public void setProfileEnabled(ComponentName who) {
+ if (!mHasFeature) {
+ return;
+ }
+ synchronized (this) {
+ // Check for permissions
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ // Check if this is the profile owner who is calling
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ Slog.d(LOG_TAG, "Enabling the profile for: " + UserHandle.getCallingUserId());
+ long id = Binder.clearCallingIdentity();
+
+ try {
+ Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId()));
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ @Override
public String getProfileOwner(int userHandle) {
if (!mHasFeature) {
return null;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 8b9f718..8392672 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -216,7 +216,7 @@
expectLastCall().atLeastOnce();
// expect to answer screen status during systemReady()
- expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+ expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
expectCurrentTime();
@@ -331,7 +331,7 @@
verifyAndReset();
// now turn screen off and verify REJECT rule
- expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
+ expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
expectSetUidNetworkRules(UID_A, true);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
@@ -341,7 +341,7 @@
verifyAndReset();
// and turn screen back on, verify ALLOW rule restored
- expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+ expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 502ee18..f5ac178 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -590,14 +590,19 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("state", (enabled ? 1 : 0));
if (enabled) {
+ Scanner scanner = null;
try {
- Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
+ scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
int card = scanner.nextInt();
int device = scanner.nextInt();
intent.putExtra("card", card);
intent.putExtra("device", device);
} catch (FileNotFoundException e) {
Slog.e(TAG, "could not open audio source PCM file", e);
+ } finally {
+ if (scanner != null) {
+ scanner.close();
+ }
}
}
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 7ae5460..8b54264 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -17,6 +17,7 @@
package com.android.server.usb;
import android.content.Context;
+import android.content.Intent;
import android.hardware.usb.UsbConfiguration;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
@@ -25,11 +26,16 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.util.Slog;
+import com.android.alsascan.AlsaCardsParser;
+import com.android.alsascan.AlsaDevicesParser;
import com.android.internal.annotations.GuardedBy;
+import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
@@ -39,7 +45,7 @@
*/
public class UsbHostManager {
private static final String TAG = UsbHostManager.class.getSimpleName();
- private static final boolean LOG = false;
+ private static final boolean DEBUG_AUDIO = false;
// contains all connected USB devices
private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
@@ -57,6 +63,15 @@
private ArrayList<UsbInterface> mNewInterfaces;
private ArrayList<UsbEndpoint> mNewEndpoints;
+ // Attributes of any connected USB audio device.
+ //TODO(pmclean) When we extend to multiple, USB Audio devices, we will need to get
+ // more clever about this.
+ private int mConnectedUsbCard = -1;
+ private int mConnectedUsbDeviceNum = -1;
+ private boolean mConnectedHasPlayback = false;
+ private boolean mConnectedHasCapture = false;
+ private boolean mConnectedHasMIDI = false;
+
@GuardedBy("mLock")
private UsbSettingsManager mCurrentSettings;
@@ -102,6 +117,48 @@
return false;
}
+ // Broadcasts the arrival/departure of a USB audio interface
+ // card - the ALSA card number of the physical interface
+ // device - the ALSA device number of the physical interface
+ // enabled - if true, we're connecting a device (it's arrived), else disconnecting
+ private void sendDeviceNotification(int card, int device, boolean enabled,
+ boolean hasPlayback, boolean hasCapture, boolean hasMIDI) {
+ // send a sticky broadcast containing current USB state
+ Intent intent = new Intent(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra("state", enabled ? 1 : 0);
+ intent.putExtra("card", card);
+ intent.putExtra("device", device);
+ intent.putExtra("hasPlayback", hasPlayback);
+ intent.putExtra("hasCapture", hasCapture);
+ intent.putExtra("hasMIDI", hasMIDI);
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ private boolean waitForAlsaFile(int card, int device, boolean capture) {
+ // These values were empirically determined.
+ final int kNumRetries = 5;
+ final int kSleepTime = 500; // ms
+ String alsaDevPath = "/dev/snd/pcmC" + card + "D" + device + (capture ? "c" : "p");
+ File alsaDevFile = new File(alsaDevPath);
+ boolean exists = false;
+ for (int retry = 0; !exists && retry < kNumRetries; retry++) {
+ exists = alsaDevFile.exists();
+ if (!exists) {
+ try {
+ Thread.sleep(kSleepTime);
+ } catch (IllegalThreadStateException ex) {
+ Slog.d(TAG, "usb: IllegalThreadStateException while waiting for ALSA file.");
+ } catch (java.lang.InterruptedException ex) {
+ Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
+ }
+ }
+ }
+
+ return exists;
+ }
+
/* Called from JNI in monitorUsbHostBus() to report new USB devices
Returns true if successful, in which case the JNI code will continue adding configurations,
interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
@@ -111,6 +168,25 @@
int deviceClass, int deviceSubclass, int deviceProtocol,
String manufacturerName, String productName, String serialNumber) {
+ if (DEBUG_AUDIO) {
+ Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
+ // Audio Class Codes:
+ // Audio: 0x01
+ // Audio Subclass Codes:
+ // undefined: 0x00
+ // audio control: 0x01
+ // audio streaming: 0x02
+ // midi streaming: 0x03
+
+ // some useful debugging info
+ Slog.d(TAG, "usb: nm:" + deviceName + " vnd:" + vendorID + " prd:" + productID + " cls:"
+ + deviceClass + " sub:" + deviceSubclass + " proto:" + deviceProtocol);
+ }
+
+ // OK this is non-obvious, but true. One can't tell if the device being attached is even
+ // potentially an audio device without parsing the interface descriptors, so punt on any
+ // such test until endUsbDeviceAdded() when we have that info.
+
if (isBlackListed(deviceName) ||
isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
return false;
@@ -135,6 +211,7 @@
mNewInterfaces = new ArrayList<UsbInterface>();
mNewEndpoints = new ArrayList<UsbEndpoint>();
}
+
return true;
}
@@ -176,6 +253,9 @@
/* Called from JNI in monitorUsbHostBus() to finish adding a new device */
private void endUsbDeviceAdded() {
+ if (DEBUG_AUDIO) {
+ Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
+ }
if (mNewInterface != null) {
mNewInterface.setEndpoints(
mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
@@ -185,6 +265,17 @@
mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
}
+ // Is there an audio interface in there?
+ final int kUsbClassId_Audio = 0x01;
+ boolean isAudioDevice = false;
+ for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < mNewInterfaces.size();
+ ntrfaceIndex++) {
+ UsbInterface ntrface = mNewInterfaces.get(ntrfaceIndex);
+ if (ntrface.getInterfaceClass() == kUsbClassId_Audio) {
+ isAudioDevice = true;
+ }
+ }
+
synchronized (mLock) {
if (mNewDevice != null) {
mNewDevice.setConfigurations(
@@ -200,10 +291,70 @@
mNewInterfaces = null;
mNewEndpoints = null;
}
+
+ if (!isAudioDevice) {
+ return; // bail
+ }
+
+ //TODO(pmclean) The "Parser" objects inspect files in "/proc/asound" which we presume is
+ // present, unlike the waitForAlsaFile() which waits on a file in /dev/snd. It is not
+ // clear why this works, or that it can be relied on going forward. Needs further
+ // research.
+ AlsaCardsParser cardsParser = new AlsaCardsParser();
+ cardsParser.scan();
+ // cardsParser.Log();
+
+ // But we need to parse the device to determine its capabilities.
+ AlsaDevicesParser devicesParser = new AlsaDevicesParser();
+ devicesParser.scan();
+ // devicesParser.Log();
+
+ // The protocol for now will be to select the last-connected (highest-numbered)
+ // Alsa Card.
+ mConnectedUsbCard = cardsParser.getNumCardRecords() - 1;
+ mConnectedUsbDeviceNum = 0;
+
+ if (!waitForAlsaFile(mConnectedUsbCard, mConnectedUsbDeviceNum, false)) {
+ return;
+ }
+
+ mConnectedHasPlayback = devicesParser.hasPlaybackDevices(mConnectedUsbCard);
+ mConnectedHasCapture = devicesParser.hasCaptureDevices(mConnectedUsbCard);
+ mConnectedHasMIDI = devicesParser.hasMIDIDevices(mConnectedUsbCard);
+
+ if (DEBUG_AUDIO) {
+ Slog.d(TAG,
+ "usb: hasPlayback:" + mConnectedHasPlayback + " hasCapture:" + mConnectedHasCapture);
+ }
+
+ sendDeviceNotification(mConnectedUsbCard,
+ mConnectedUsbDeviceNum,
+ true,
+ mConnectedHasPlayback,
+ mConnectedHasCapture,
+ mConnectedHasMIDI);
}
/* Called from JNI in monitorUsbHostBus to report USB device removal */
private void usbDeviceRemoved(String deviceName) {
+ if (DEBUG_AUDIO) {
+ Slog.d(TAG, "usb:UsbHostManager.usbDeviceRemoved() nm:" + deviceName);
+ }
+
+ if (mConnectedUsbCard != -1 && mConnectedUsbDeviceNum != -1) {
+ sendDeviceNotification(mConnectedUsbCard,
+ mConnectedUsbDeviceNum,
+ false,
+ mConnectedHasPlayback,
+ mConnectedHasCapture,
+ mConnectedHasMIDI);
+ mConnectedUsbCard = -1;
+ mConnectedUsbDeviceNum = -1;
+ mConnectedHasPlayback = false;
+ mConnectedHasCapture = false;
+ mConnectedHasMIDI = false;
+ }
+
synchronized (mLock) {
UsbDevice device = mDevices.remove(deviceName);
if (device != null) {
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 46d09f6..be13acc 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -137,7 +137,6 @@
/**
* Get the signal level as an asu value between 0..97, 99 is unknown
- * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
*/
@Override
public int getAsuLevel() {
@@ -342,7 +341,7 @@
/**
* Construct a SignalStrength object from the given parcel
- * where the TYPE_LTE token is already been processed.
+ * where the TYPE_CDMA token is already been processed.
*/
private CellSignalStrengthCdma(Parcel in) {
// CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio are written into
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index daef37a..992ef4b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -78,6 +78,12 @@
}
@Override
+ public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+
public int[] getPackageGids(String packageName) throws NameNotFoundException {
throw new UnsupportedOperationException();
}
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index bf35db4..a0b2d1a 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -97,6 +97,7 @@
setLowProfile(true);
setFullscreen(true);
setContentView(R.layout.dream);
+ setScreenBright(false);
mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 1f2342a..4dd1446 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -453,13 +453,13 @@
}
@Override
- public boolean clearWindowContentRenderStats(IBinder token) {
+ public boolean clearWindowContentFrameStats(IBinder token) {
// TODO Auto-generated method stub
return false;
}
@Override
- public WindowContentFrameStats getWindowContentRenderStats(IBinder token) {
+ public WindowContentFrameStats getWindowContentFrameStats(IBinder token) {
// TODO Auto-generated method stub
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index b9f2ed9..4eb70aa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -28,7 +28,7 @@
public class BridgePowerManager implements IPowerManager {
@Override
- public boolean isScreenOn() throws RemoteException {
+ public boolean isInteractive() throws RemoteException {
return true;
}