Merge "Rename related users to profiles."
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..3835942
--- /dev/null
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -0,0 +1,240 @@
+/*
+ * 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 hasCaptureDevices() {
+ return mHasCaptureDevices;
+ }
+
+ public boolean hasMIDIDevices() {
+ return mHasMIDIDevices;
+ }
+
+ 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/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index 4ca06ed..7036aea 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -124,4 +124,12 @@
int type, String domain, String path, long mode, long mtime,
int token, IBackupManager callbackBinder);
+ /**
+ * Out of band: instruct the agent to crash within the client process. This is used
+ * when the backup infrastructure detects a semantic error post-hoc and needs to
+ * pass the problem back to the app.
+ *
+ * @param message The message to be passed to the agent's application in an exception.
+ */
+ void fail(String message);
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 8efc14f..cf14202 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -121,8 +121,8 @@
*/
public static final int FLAG_ONE_SHOT = 1<<30;
/**
- * Flag indicating that if the described PendingIntent already
- * exists, then simply return null instead of creating it.
+ * Flag indicating that if the described PendingIntent does not
+ * already exist, then simply return null instead of creating it.
* For use with {@link #getActivity}, {@link #getBroadcast}, and
* {@link #getService}.
*/
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 67c772b..3c31f8d 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -128,6 +128,13 @@
Handler mHandler = null;
+ Handler getHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+ return mHandler;
+ }
+
class SharedPrefsSynchronizer implements Runnable {
public final CountDownLatch mLatch = new CountDownLatch(1);
@@ -140,12 +147,9 @@
// Syncing shared preferences deferred writes needs to happen on the main looper thread
private void waitForSharedPrefs() {
- if (mHandler == null) {
- mHandler = new Handler(Looper.getMainLooper());
- }
-
+ Handler h = getHandler();
final SharedPrefsSynchronizer s = new SharedPrefsSynchronizer();
- mHandler.postAtFrontOfQueue(s);
+ h.postAtFrontOfQueue(s);
try {
s.mLatch.await();
} catch (InterruptedException e) { /* ignored */ }
@@ -680,5 +684,23 @@
}
}
}
+
+ @Override
+ public void fail(String message) {
+ getHandler().post(new FailRunnable(message));
+ }
+ }
+
+ static class FailRunnable implements Runnable {
+ private String mMessage;
+
+ FailRunnable(String message) {
+ mMessage = message;
+ }
+
+ @Override
+ public void run() {
+ throw new IllegalStateException(mMessage);
+ }
}
}
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index 845784f..fc5fb3d 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -85,11 +85,6 @@
* @throws IOException if the write failed
*/
public int writeEntityHeader(String key, int dataSize) throws IOException {
- if (key != null && key.charAt(0) >= 0xff00) {
- if (Process.myUid() != Process.SYSTEM_UID) {
- throw new IllegalArgumentException("Invalid key " + key);
- }
- }
int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
if (result >= 0) {
return result;
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 2c8a5c2..ecc461e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -335,7 +335,9 @@
mRepeatingRequestId = REQUEST_ID_NONE;
// Queue for deletion after in-flight requests finish
- mRepeatingRequestIdDeletedList.add(requestId);
+ if (mCaptureListenerMap.get(requestId) != null) {
+ mRepeatingRequestIdDeletedList.add(requestId);
+ }
try {
mRemoteDevice.cancelRequest(requestId);
@@ -367,8 +369,6 @@
}
mRepeatingRequestId = REQUEST_ID_NONE;
- mRepeatingRequestIdDeletedList.clear();
- mCaptureListenerMap.clear();
}
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 057f516..3241693 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,10 +16,11 @@
package android.os;
-import android.net.LocalSocketAddress;
import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.util.Log;
-import dalvik.system.Zygote;
+
+import com.android.internal.os.Zygote;
import java.io.BufferedWriter;
import java.io.DataInputStream;
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index b97734e..4180860 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -694,6 +694,36 @@
return _result;
}
+ public String getPassword() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ String _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_getPassword, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readString();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public void clearPassword() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ String _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_clearPassword, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
public StorageVolume[] getVolumeList() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -846,7 +876,11 @@
static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34;
- static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 36;
+ static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 35;
+
+ static final int TRANSACTION_getPassword = IBinder.FIRST_CALL_TRANSACTION + 36;
+
+ static final int TRANSACTION_clearPassword = IBinder.FIRST_CALL_TRANSACTION + 37;
/**
* Cast an IBinder object into an IMountService interface, generating a
@@ -1208,6 +1242,19 @@
reply.writeInt(result);
return true;
}
+ case TRANSACTION_getPassword: {
+ data.enforceInterface(DESCRIPTOR);
+ String result = getPassword();
+ reply.writeNoException();
+ reply.writeString(result);
+ return true;
+ }
+ case TRANSACTION_clearPassword: {
+ data.enforceInterface(DESCRIPTOR);
+ clearPassword();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1446,4 +1493,15 @@
* @return PasswordType
*/
public int getPasswordType() throws RemoteException;
+
+ /**
+ * Get password from vold
+ * @return password or empty string
+ */
+ public String getPassword() throws RemoteException;
+
+ /**
+ * Securely clear password from vold
+ */
+ public void clearPassword() throws RemoteException;
}
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index b8635b8..05f3a1c 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -73,7 +73,8 @@
public static final String[] INDEXABLES_RAW_COLUMNS = new String[] {
RawData.COLUMN_RANK,
RawData.COLUMN_TITLE,
- RawData.COLUMN_SUMMARY,
+ RawData.COLUMN_SUMMARY_ON,
+ RawData.COLUMN_SUMMARY_OFF,
RawData.COLUMN_KEYWORDS,
RawData.COLUMN_SCREEN_TITLE,
RawData.COLUMN_CLASS_NAME,
@@ -123,9 +124,14 @@
public static final String COLUMN_TITLE = "title";
/**
- * Summary's raw data.
+ * Summary's raw data when the data is "ON".
*/
- public static final String COLUMN_SUMMARY = "summary";
+ public static final String COLUMN_SUMMARY_ON = "summaryOn";
+
+ /**
+ * Summary's raw data when the data is "OFF".
+ */
+ public static final String COLUMN_SUMMARY_OFF = "summaryOff";
/**
* Keywords' raw data.
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index a92f89d..4f646e1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -182,7 +182,7 @@
public static boolean sSystemRendererDisabled = false;
/** @hide */
- public static boolean sUseRenderThread = true;
+ public static boolean sUseRenderThread = false;
private boolean mEnabled;
private boolean mRequested = true;
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 1766f7b..3301cbe 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -26,8 +26,6 @@
import libcore.io.IoUtils;
-import dalvik.system.Zygote;
-
/**
* Startup class for the wrapper process.
* @hide
@@ -94,7 +92,7 @@
* @param niceName The nice name for the application, or null if none.
* @param targetSdkVersion The target SDK version for the app.
* @param pipeFd The pipe to which the application's pid should be written, or null if none.
- * @param args Arguments for {@link RuntimeInit.main}.
+ * @param args Arguments for {@link RuntimeInit#main}.
*/
public static void execApplication(String invokeWith, String niceName,
int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
new file mode 100644
index 0000000..c5fa0a1
--- /dev/null
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -0,0 +1,164 @@
+/*
+ * 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.internal.os;
+
+
+import dalvik.system.ZygoteHooks;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+
+/** @hide */
+public final class Zygote {
+ /*
+ * Bit values for "debugFlags" argument. The definitions are duplicated
+ * in the native code.
+ */
+
+ /** enable debugging over JDWP */
+ public static final int DEBUG_ENABLE_DEBUGGER = 1;
+ /** enable JNI checks */
+ public static final int DEBUG_ENABLE_CHECKJNI = 1 << 1;
+ /** enable Java programming language "assert" statements */
+ public static final int DEBUG_ENABLE_ASSERT = 1 << 2;
+ /** disable the JIT compiler */
+ public static final int DEBUG_ENABLE_SAFEMODE = 1 << 3;
+ /** Enable logging of third-party JNI activity. */
+ public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
+
+ /** No external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_NONE = 0;
+ /** Single-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
+ /** Multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
+ /** All multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
+
+ private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+
+ private Zygote() {}
+
+ /**
+ * Forks a new VM instance. The current VM must have been started
+ * with the -Xzygote flag. <b>NOTE: new instance keeps all
+ * root capabilities. The new process is expected to call capset()</b>.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param debugFlags bit flags that enable debugging features.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ * @param seInfo null-ok a string specifying SELinux information for
+ * the new process.
+ * @param niceName null-ok a string specifying the process name.
+ * @param fdsToClose an array of ints, holding one or more POSIX
+ * file descriptor numbers that are to be closed by the child
+ * (and replaced by /dev/null) after forking. An integer value
+ * of -1 in any entry in the array means "ignore this one".
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error.
+ */
+ public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose) {
+ VM_HOOKS.preFork();
+ int pid = nativeForkAndSpecialize(
+ uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose);
+ VM_HOOKS.postForkCommon();
+ return pid;
+ }
+
+ native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose);
+
+ /**
+ * Special method to start the system server process. In addition to the
+ * common actions performed in forkAndSpecialize, the pid of the child
+ * process is recorded such that the death of the child process will cause
+ * zygote to exit.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param debugFlags bit flags that enable debugging features.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ * @param permittedCapabilities argument for setcap()
+ * @param effectiveCapabilities argument for setcap()
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error.
+ */
+ public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
+ VM_HOOKS.preFork();
+ int pid = nativeForkSystemServer(
+ uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
+ VM_HOOKS.postForkCommon();
+ return pid;
+ }
+
+ native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
+
+ private static void callPostForkChildHooks(int debugFlags) {
+ VM_HOOKS.postForkChild(debugFlags);
+ }
+
+
+ /**
+ * Executes "/system/bin/sh -c <command>" using the exec() system call.
+ * This method throws a runtime exception if exec() failed, otherwise, this
+ * method never returns.
+ *
+ * @param command The shell command to execute.
+ */
+ public static void execShell(String command) {
+ String[] args = { "/system/bin/sh", "-c", command };
+ try {
+ Libcore.os.execv(args[0], args);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Appends quotes shell arguments to the specified string builder.
+ * The arguments are quoted using single-quotes, escaped if necessary,
+ * prefixed with a space, and appended to the command.
+ *
+ * @param command A string builder for the shell command being constructed.
+ * @param args An array of argument strings to be quoted and appended to the command.
+ * @see #execShell(String)
+ */
+ public static void appendQuotedShellArgs(StringBuilder command, String[] args) {
+ for (String arg : args) {
+ command.append(" '").append(arg.replace("'", "'\\''")).append("'");
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index f9a1f89..aad534c 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -24,7 +24,6 @@
import android.util.Log;
import dalvik.system.PathClassLoader;
-import dalvik.system.Zygote;
import java.io.BufferedReader;
import java.io.DataInputStream;
@@ -807,7 +806,7 @@
/**
* Applies invoke-with system properties to the zygote arguments.
*
- * @param parsedArgs non-null; zygote args
+ * @param args non-null; zygote args
*/
public static void applyInvokeWithSystemProperty(Arguments args) {
if (args.invokeWith == null && args.niceName != null) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 05c57e8..66cc120 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -32,7 +32,6 @@
import android.util.Log;
import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
import libcore.io.IoUtils;
import libcore.io.Libcore;
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 91056f1..9501f92 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -28,6 +28,7 @@
boolean checkPattern(in String pattern, int userId);
void setLockPassword(in String password, int userId);
boolean checkPassword(in String password, int userId);
+ boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
void removeUser(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 4752da5..b9bc54d 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -333,6 +333,20 @@
}
/**
+ * Check to see if vold already has the password.
+ * Note that this also clears vold's copy of the password.
+ * @return Whether the vold password matches or not.
+ */
+ public boolean checkVoldPassword() {
+ final int userId = getCurrentOrCallingUserId();
+ try {
+ return getLockSettings().checkVoldPassword(userId);
+ } catch (RemoteException re) {
+ return false;
+ }
+ }
+
+ /**
* Check to see if a password matches any of the passwords stored in the
* password history.
*
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 26cb4e5..36ed344 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -32,6 +32,7 @@
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
@@ -260,13 +261,23 @@
mPathPaint.setAntiAlias(true);
mPathPaint.setDither(true);
- mPathPaint.setColor(Color.WHITE); // TODO this should be from the style
+
+ int defaultColor = Color.WHITE;
+ TypedValue outValue = new TypedValue();
+ if (context.getTheme().resolveAttribute(android.R.attr.textColorPrimary, outValue, true)) {
+ defaultColor = context.getResources().getColor(outValue.resourceId);
+ }
+
+ final int color = a.getColor(R.styleable.LockPatternView_pathColor, defaultColor);
+ mPathPaint.setColor(color);
+
mPathPaint.setAlpha(mStrokeAlpha);
mPathPaint.setStyle(Paint.Style.STROKE);
mPathPaint.setStrokeJoin(Paint.Join.ROUND);
mPathPaint.setStrokeCap(Paint.Cap.ROUND);
// lot's of bitmaps!
+ // TODO: those bitmaps are hardcoded to the Holo Theme which should not be the case!
mBitmapBtnDefault = getBitmapFor(R.drawable.btn_code_lock_default_holo);
mBitmapBtnTouched = getBitmapFor(R.drawable.btn_code_lock_touched_holo);
mBitmapCircleDefault = getBitmapFor(R.drawable.indicator_code_lock_point_area_default_holo);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 51c5a86..711f28a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -151,7 +151,8 @@
android_content_res_ObbScanner.cpp \
android_content_res_Configuration.cpp \
android_animation_PropertyValuesHolder.cpp \
- com_android_internal_net_NetworkStatsFactory.cpp
+ com_android_internal_net_NetworkStatsFactory.cpp \
+ com_android_internal_os_Zygote.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
@@ -177,7 +178,8 @@
external/harfbuzz_ng/src \
external/zlib \
frameworks/opt/emoji \
- libcore/include
+ libcore/include \
+ $(call include-path-for, audio-utils) \
LOCAL_SHARED_LIBRARIES := \
libmemtrack \
@@ -213,7 +215,8 @@
libjpeg \
libusbhost \
libharfbuzz_ng \
- libz
+ libz \
+ libaudioutils \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9a7a5f9..6afeb86 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -178,6 +178,7 @@
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_Zygote(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -1244,6 +1245,7 @@
REG_JNI(register_android_net_TrafficStats),
REG_JNI(register_android_os_MemoryFile),
REG_JNI(register_com_android_internal_os_ZygoteInit),
+ REG_JNI(register_com_android_internal_os_Zygote),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
REG_JNI(register_android_hardware_SensorManager),
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 9449bac..d8faaf3 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -166,7 +166,7 @@
ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
}
- uint32_t nbChannels = popcount(channelMask);
+ uint32_t channelCount = popcount(channelMask);
// compare the format against the Java constants
audio_format_t format = audioFormatToNative(audioFormat);
@@ -181,7 +181,7 @@
ALOGE("Error creating AudioRecord: frameCount is 0.");
return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
}
- size_t frameSize = nbChannels * bytesPerSample;
+ size_t frameSize = channelCount * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
if ((uint32_t(source) >= AUDIO_SOURCE_CNT) && (uint32_t(source) != AUDIO_SOURCE_HOTWORD)) {
@@ -500,17 +500,17 @@
// returns 0 if the parameter combination is not supported.
// return -1 if there was an error querying the buffer size.
static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
- jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+ jint sampleRateInHertz, jint channelCount, jint audioFormat) {
ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
- sampleRateInHertz, nbChannels, audioFormat);
+ sampleRateInHertz, channelCount, audioFormat);
size_t frameCount = 0;
audio_format_t format = audioFormatToNative(audioFormat);
status_t result = AudioRecord::getMinFrameCount(&frameCount,
sampleRateInHertz,
format,
- audio_channel_in_mask_from_count(nbChannels));
+ audio_channel_in_mask_from_count(channelCount));
if (result == BAD_VALUE) {
return 0;
@@ -518,7 +518,7 @@
if (result != NO_ERROR) {
return -1;
}
- return frameCount * nbChannels * audio_bytes_per_sample(format);
+ return frameCount * channelCount * audio_bytes_per_sample(format);
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index d79b2a4..162d0c4 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -26,6 +26,7 @@
#include <utils/Log.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
+#include <audio_utils/primitives.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>
@@ -219,14 +220,14 @@
// Java channel masks don't map directly to the native definition, but it's a simple shift
// to skip the two deprecated channel configurations "default" and "mono".
- uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
+ audio_channel_mask_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
if (!audio_is_output_channel(nativeChannelMask)) {
ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
}
- int nbChannels = popcount(nativeChannelMask);
+ uint32_t channelCount = popcount(nativeChannelMask);
// check the stream type
audio_stream_type_t atStreamType;
@@ -269,7 +270,7 @@
// compute the frame count
const size_t bytesPerSample = audio_bytes_per_sample(format);
- size_t frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
+ size_t frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
@@ -550,10 +551,8 @@
}
int count = sizeInBytes;
int16_t *dst = (int16_t *)track->sharedBuffer()->pointer();
- const int8_t *src = (const int8_t *)(data + offsetInBytes);
- while (count--) {
- *dst++ = (int16_t)(*src++^0x80) << 8;
- }
+ const uint8_t *src = (const uint8_t *)(data + offsetInBytes);
+ memcpy_to_i16_from_u8(dst, src, count);
// even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
// the 8bit mixer restriction from the user of this function
written = sizeInBytes;
@@ -872,7 +871,7 @@
// returns the minimum required size for the successful creation of a streaming AudioTrack
// returns -1 if there was an error querying the hardware.
static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
- jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+ jint sampleRateInHertz, jint channelCount, jint audioFormat) {
size_t frameCount;
const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
@@ -884,21 +883,26 @@
}
const audio_format_t format = audioFormatToNative(audioFormat);
const size_t bytesPerSample = audio_bytes_per_sample(format);
- return frameCount * nbChannels * bytesPerSample;
+ return frameCount * channelCount * bytesPerSample;
}
// ----------------------------------------------------------------------------
-static void
+static jint
android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
{
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
if (lpTrack == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
- return;
+ return -1;
}
- lpTrack->setAuxEffectSendLevel(level);
+ status_t status = lpTrack->setAuxEffectSendLevel(level);
+ if (status != NO_ERROR) {
+ ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
+ level, status);
+ }
+ return (jint) status;
}
// ----------------------------------------------------------------------------
@@ -954,7 +958,7 @@
{"native_get_min_buff_size",
"(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
{"native_setAuxEffectSendLevel",
- "(F)V", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
+ "(F)I", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
{"native_attachAuxEffect",
"(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
new file mode 100644
index 0000000..a61fa87
--- /dev/null
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "android_runtime/AndroidRuntime.h"
+
+// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include <grp.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "cutils/fs.h"
+#include "cutils/multiuser.h"
+#include "cutils/sched_policy.h"
+#include "utils/String8.h"
+#include "JNIHelp.h"
+#include "ScopedLocalRef.h"
+#include "ScopedPrimitiveArray.h"
+#include "ScopedUtfChars.h"
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+#include <selinux/android.h>
+
+#if defined(__linux__)
+#include <sys/personality.h>
+#include <sys/utsname.h>
+#if defined(HAVE_ANDROID_OS)
+#include <sys/capability.h>
+#endif
+#endif
+
+namespace {
+
+using android::String8;
+
+static pid_t gSystemServerPid = 0;
+
+static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
+static jclass gZygoteClass;
+static jmethodID gCallPostForkChildHooks;
+
+// Must match values in com.android.internal.os.Zygote.
+enum MountExternalKind {
+ MOUNT_EXTERNAL_NONE = 0,
+ MOUNT_EXTERNAL_SINGLEUSER = 1,
+ MOUNT_EXTERNAL_MULTIUSER = 2,
+ MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+};
+
+static void RuntimeAbort(JNIEnv* env) {
+ env->FatalError("RuntimeAbort");
+}
+
+// This signal handler is for zygote mode, since the zygote must reap its children
+static void SigChldHandler(int /*signal_number*/) {
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ // Log process-death status that we care about. In general it is
+ // not safe to call LOG(...) from a signal handler because of
+ // possible reentrancy. However, we know a priori that the
+ // current implementation of LOG() is safe to call from a SIGCHLD
+ // handler in the zygote process. If the LOG() implementation
+ // changes its locking strategy or its use of syscalls within the
+ // lazy-init critical section, its use here may become unsafe.
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status)) {
+ ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+ } else if (false) {
+ ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+ }
+ } else if (WIFSIGNALED(status)) {
+ if (WTERMSIG(status) != SIGKILL) {
+ ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+ } else if (false) {
+ ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+ }
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status)) {
+ ALOGI("Process %d dumped core.", pid);
+ }
+#endif /* ifdef WCOREDUMP */
+ }
+
+ // If the just-crashed process is the system_server, bring down zygote
+ // so that it is restarted by init and system server will be restarted
+ // from there.
+ if (pid == gSystemServerPid) {
+ ALOGE("Exit zygote because system server (%d) has terminated");
+ kill(getpid(), SIGKILL);
+ }
+ }
+
+ if (pid < 0) {
+ ALOGW("Zygote SIGCHLD error in waitpid: %d", errno);
+ }
+}
+
+// Configures the SIGCHLD handler for the zygote process. This is configured
+// very late, because earlier in the runtime we may fork() and exec()
+// other processes, and we want to waitpid() for those rather than
+// have them be harvested immediately.
+//
+// This ends up being called repeatedly before each fork(), but there's
+// no real harm in that.
+static void SetSigChldHandler() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SigChldHandler;
+
+ int err = sigaction(SIGCHLD, &sa, NULL);
+ if (err < 0) {
+ ALOGW("Error setting SIGCHLD handler: %d", errno);
+ }
+}
+
+// Sets the SIGCHLD handler back to default behavior in zygote children.
+static void UnsetSigChldHandler() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+
+ int err = sigaction(SIGCHLD, &sa, NULL);
+ if (err < 0) {
+ ALOGW("Error unsetting SIGCHLD handler: %d", errno);
+ }
+}
+
+// Calls POSIX setgroups() using the int[] object as an argument.
+// A NULL argument is tolerated.
+static void SetGids(JNIEnv* env, jintArray javaGids) {
+ if (javaGids == NULL) {
+ return;
+ }
+
+ ScopedIntArrayRO gids(env, javaGids);
+ if (gids.get() == NULL) {
+ RuntimeAbort(env);
+ }
+ int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
+ if (rc == -1) {
+ ALOGE("setgroups failed");
+ RuntimeAbort(env);
+ }
+}
+
+// Sets the resource limits via setrlimit(2) for the values in the
+// two-dimensional array of integers that's passed in. The second dimension
+// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
+// treated as an empty array.
+static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
+ if (javaRlimits == NULL) {
+ return;
+ }
+
+ rlimit rlim;
+ memset(&rlim, 0, sizeof(rlim));
+
+ for (int i = 0; i < env->GetArrayLength(javaRlimits); ++i) {
+ ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
+ ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
+ if (javaRlimit.size() != 3) {
+ ALOGE("rlimits array must have a second dimension of size 3");
+ RuntimeAbort(env);
+ }
+
+ rlim.rlim_cur = javaRlimit[1];
+ rlim.rlim_max = javaRlimit[2];
+
+ int rc = setrlimit(javaRlimit[0], &rlim);
+ if (rc == -1) {
+ ALOGE("setrlimit(%d, {%d, %d}) failed", javaRlimit[0], rlim.rlim_cur, rlim.rlim_max);
+ RuntimeAbort(env);
+ }
+ }
+}
+
+#if defined(HAVE_ANDROID_OS)
+
+// The debug malloc library needs to know whether it's the zygote or a child.
+extern "C" int gMallocLeakZygoteChild;
+
+static void EnableKeepCapabilities(JNIEnv* env) {
+ int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+ if (rc == -1) {
+ ALOGE("prctl(PR_SET_KEEPCAPS) failed");
+ RuntimeAbort(env);
+ }
+}
+
+static void DropCapabilitiesBoundingSet(JNIEnv* env) {
+ for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+ int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+ if (rc == -1) {
+ if (errno == EINVAL) {
+ ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
+ "your kernel is compiled with file capabilities support");
+ } else {
+ ALOGE("prctl(PR_CAPBSET_DROP) failed");
+ RuntimeAbort(env);
+ }
+ }
+ }
+}
+
+static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ memset(&capdata, 0, sizeof(capdata));
+ capdata[0].effective = effective;
+ capdata[1].effective = effective >> 32;
+ capdata[0].permitted = permitted;
+ capdata[1].permitted = permitted >> 32;
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ ALOGE("capset(%lld, %lld) failed", permitted, effective);
+ RuntimeAbort(env);
+ }
+}
+
+static void SetSchedulerPolicy(JNIEnv* env) {
+ errno = -set_sched_policy(0, SP_DEFAULT);
+ if (errno != 0) {
+ ALOGE("set_sched_policy(0, SP_DEFAULT) failed");
+ RuntimeAbort(env);
+ }
+}
+
+#else
+
+static int gMallocLeakZygoteChild = 0;
+
+static void EnableKeepCapabilities(JNIEnv*) {}
+static void DropCapabilitiesBoundingSet(JNIEnv*) {}
+static void SetCapabilities(JNIEnv*, int64_t, int64_t) {}
+static void SetSchedulerPolicy(JNIEnv*) {}
+
+#endif
+
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
+ if (mount_mode == MOUNT_EXTERNAL_NONE) {
+ return true;
+ }
+
+ // See storage config details at http://source.android.com/tech/storage/
+ userid_t user_id = multiuser_get_user_id(uid);
+
+ // Create a second private mount namespace for our process
+ if (unshare(CLONE_NEWNS) == -1) {
+ ALOGW("Failed to unshare(): %d", errno);
+ return false;
+ }
+
+ // Create bind mounts to expose external storage
+ if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ // These paths must already be created by init.rc
+ const char* source = getenv("EMULATED_STORAGE_SOURCE");
+ const char* target = getenv("EMULATED_STORAGE_TARGET");
+ const char* legacy = getenv("EXTERNAL_STORAGE");
+ if (source == NULL || target == NULL || legacy == NULL) {
+ ALOGW("Storage environment undefined; unable to provide external storage");
+ return false;
+ }
+
+ // Prepare source paths
+
+ // /mnt/shell/emulated/0
+ const String8 source_user(String8::format("%s/%d", source, user_id));
+ // /storage/emulated/0
+ const String8 target_user(String8::format("%s/%d", target, user_id));
+
+ if (fs_prepare_dir(source_user.string(), 0000, 0, 0) == -1
+ || fs_prepare_dir(target_user.string(), 0000, 0, 0) == -1) {
+ return false;
+ }
+
+ if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ // Mount entire external storage tree for all users
+ if (TEMP_FAILURE_RETRY(mount(source, target, NULL, MS_BIND, NULL)) == -1) {
+ ALOGW("Failed to mount %s to %s :%d", source, target, errno);
+ return false;
+ }
+ } else {
+ // Only mount user-specific external storage
+ if (TEMP_FAILURE_RETRY(
+ mount(source_user.string(), target_user.string(), NULL, MS_BIND, NULL)) == -1) {
+ ALOGW("Failed to mount %s to %s: %d", source_user.string(), target_user.string(), errno);
+ return false;
+ }
+ }
+
+ if (fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+ return false;
+ }
+
+ // Finally, mount user-specific path into place for legacy users
+ if (TEMP_FAILURE_RETRY(
+ mount(target_user.string(), legacy, NULL, MS_BIND | MS_REC, NULL)) == -1) {
+ ALOGW("Failed to mount %s to %s: %d", target_user.string(), legacy, errno);
+ return false;
+ }
+ } else {
+ ALOGW("Mount mode %d unsupported", mount_mode);
+ return false;
+ }
+
+ return true;
+}
+
+#if defined(__linux__)
+static bool NeedsNoRandomizeWorkaround() {
+#if !defined(__arm__)
+ return false;
+#else
+ int major;
+ int minor;
+ struct utsname uts;
+ if (uname(&uts) == -1) {
+ return false;
+ }
+
+ if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+ return false;
+ }
+
+ // Kernels before 3.4.* need the workaround.
+ return (major < 3) || ((major == 3) && (minor < 4));
+#endif
+}
+#endif
+
+// Utility to close down the Zygote socket file descriptors while
+// the child is still running as root with Zygote's privileges. Each
+// descriptor (if any) is closed via dup2(), replacing it with a valid
+// (open) descriptor to /dev/null.
+
+static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) {
+ if (!fdsToClose) {
+ return;
+ }
+ jsize count = env->GetArrayLength(fdsToClose);
+ jint *ar = env->GetIntArrayElements(fdsToClose, 0);
+ if (!ar) {
+ ALOGE("Bad fd array");
+ RuntimeAbort(env);
+ }
+ jsize i;
+ int devnull;
+ for (i = 0; i < count; i++) {
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ ALOGE("Failed to open /dev/null");
+ RuntimeAbort(env);
+ continue;
+ }
+ ALOGV("Switching descriptor %d to /dev/null: %d", ar[i], errno);
+ if (dup2(devnull, ar[i]) < 0) {
+ ALOGE("Failed dup2() on descriptor %d", ar[i]);
+ RuntimeAbort(env);
+ }
+ close(devnull);
+ }
+}
+
+void SetThreadName(const char* thread_name) {
+ bool hasAt = false;
+ bool hasDot = false;
+ const char* s = thread_name;
+ while (*s) {
+ if (*s == '.') {
+ hasDot = true;
+ } else if (*s == '@') {
+ hasAt = true;
+ }
+ s++;
+ }
+ const int len = s - thread_name;
+ if (len < 15 || hasAt || !hasDot) {
+ s = thread_name;
+ } else {
+ s = thread_name + len - 15;
+ }
+ // pthread_setname_np fails rather than truncating long strings.
+ char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+ strlcpy(buf, s, sizeof(buf)-1);
+ errno = pthread_setname_np(pthread_self(), buf);
+ if (errno != 0) {
+ ALOGW("Unable to set the name of current thread to '%s'", buf);
+ }
+}
+
+// Utility routine to fork zygote and specialize the child process.
+static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
+ jint debug_flags, jobjectArray javaRlimits,
+ jlong permittedCapabilities, jlong effectiveCapabilities,
+ jint mount_external,
+ jstring java_se_info, jstring java_se_name,
+ bool is_system_server, jintArray fdsToClose) {
+ SetSigChldHandler();
+
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ // The child process.
+ gMallocLeakZygoteChild = 1;
+
+ // Clean up any descriptors which must be closed immediately
+ DetachDescriptors(env, fdsToClose);
+
+ // Keep capabilities across UID change, unless we're staying root.
+ if (uid != 0) {
+ EnableKeepCapabilities(env);
+ }
+
+ DropCapabilitiesBoundingSet(env);
+
+ if (!MountEmulatedStorage(uid, mount_external)) {
+ ALOGW("Failed to mount emulated storage: %d", errno);
+ if (errno == ENOTCONN || errno == EROFS) {
+ // When device is actively encrypting, we get ENOTCONN here
+ // since FUSE was mounted before the framework restarted.
+ // When encrypted device is booting, we get EROFS since
+ // FUSE hasn't been created yet by init.
+ // In either case, continue without external storage.
+ } else {
+ ALOGE("Cannot continue without emulated storage");
+ RuntimeAbort(env);
+ }
+ }
+
+ SetGids(env, javaGids);
+
+ SetRLimits(env, javaRlimits);
+
+ int rc = setresgid(gid, gid, gid);
+ if (rc == -1) {
+ ALOGE("setresgid(%d) failed", gid);
+ RuntimeAbort(env);
+ }
+
+ rc = setresuid(uid, uid, uid);
+ if (rc == -1) {
+ ALOGE("setresuid(%d) failed", uid);
+ RuntimeAbort(env);
+ }
+
+#if defined(__linux__)
+ if (NeedsNoRandomizeWorkaround()) {
+ // Work around ARM kernel ASLR lossage (http://b/5817320).
+ int old_personality = personality(0xffffffff);
+ int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+ if (new_personality == -1) {
+ ALOGW("personality(%d) failed", new_personality);
+ }
+ }
+#endif
+
+ SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+
+ SetSchedulerPolicy(env);
+
+#if defined(HAVE_ANDROID_OS)
+ { // NOLINT(whitespace/braces)
+ const char* se_info_c_str = NULL;
+ ScopedUtfChars* se_info = NULL;
+ if (java_se_info != NULL) {
+ se_info = new ScopedUtfChars(env, java_se_info);
+ se_info_c_str = se_info->c_str();
+ if (se_info_c_str == NULL) {
+ ALOGE("se_info_c_str == NULL");
+ RuntimeAbort(env);
+ }
+ }
+ const char* se_name_c_str = NULL;
+ ScopedUtfChars* se_name = NULL;
+ if (java_se_name != NULL) {
+ se_name = new ScopedUtfChars(env, java_se_name);
+ se_name_c_str = se_name->c_str();
+ if (se_name_c_str == NULL) {
+ ALOGE("se_name_c_str == NULL");
+ RuntimeAbort(env);
+ }
+ }
+ rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+ if (rc == -1) {
+ ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+ is_system_server, se_info_c_str, se_name_c_str);
+ RuntimeAbort(env);
+ }
+
+ // Make it easier to debug audit logs by setting the main thread's name to the
+ // nice name rather than "app_process".
+ if (se_info_c_str == NULL && is_system_server) {
+ se_name_c_str = "system_server";
+ }
+ if (se_info_c_str != NULL) {
+ SetThreadName(se_name_c_str);
+ }
+
+ delete se_info;
+ delete se_name;
+ }
+#else
+ UNUSED(is_system_server);
+ UNUSED(java_se_info);
+ UNUSED(java_se_name);
+#endif
+
+ UnsetSigChldHandler();
+
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags);
+ if (env->ExceptionCheck()) {
+ ALOGE("Error calling post fork hooks.");
+ RuntimeAbort(env);
+ }
+ } else if (pid > 0) {
+ // the parent process
+ }
+ return pid;
+}
+} // anonymous namespace
+
+namespace android {
+
+static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
+ JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+ jint debug_flags, jobjectArray rlimits,
+ jint mount_external, jstring se_info, jstring se_name,
+ jintArray fdsToClose) {
+ return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
+ rlimits, 0, 0, mount_external, se_info, se_name, false, fdsToClose);
+}
+
+static jint com_android_internal_os_Zygote_nativeForkSystemServer(
+ JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
+ jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
+ jlong effectiveCapabilities) {
+ pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
+ debug_flags, rlimits,
+ permittedCapabilities, effectiveCapabilities,
+ MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL);
+ if (pid > 0) {
+ // The zygote process checks whether the child process has died or not.
+ ALOGI("System server process %d has been created", pid);
+ gSystemServerPid = pid;
+ // There is a slight window that the system server process has crashed
+ // but it went unnoticed because we haven't published its pid yet. So
+ // we recheck here just to make sure that all is well.
+ int status;
+ if (waitpid(pid, &status, WNOHANG) == pid) {
+ ALOGE("System server process %d has died. Restarting Zygote!", pid);
+ RuntimeAbort(env);
+ }
+ }
+ return pid;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I",
+ (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
+ { "nativeForkSystemServer", "(II[II[[IJJ)I",
+ (void *) com_android_internal_os_Zygote_nativeForkSystemServer }
+};
+
+int register_com_android_internal_os_Zygote(JNIEnv* env) {
+ gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
+ if (gZygoteClass == NULL) {
+ RuntimeAbort(env);
+ }
+ gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks", "(I)V");
+
+ return AndroidRuntime::registerNativeMethods(env, "com/android/internal/os/Zygote",
+ gMethods, NELEM(gMethods));
+}
+} // namespace android
+
diff --git a/core/res/res/drawable-hdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..406bf58
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..409d3cd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..b07da0c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..9d7b25f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-hdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index 717ec1a..0000000
--- a/core/res/res/drawable-hdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..e49ad54
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..1222711
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..d0fcc25
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..992a8ff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..51a895d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..2f59488
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..e0a2ba1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..d37e8ee
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..0c604d9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..2c3f4ff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..991c50e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..05fb919
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..219d311
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..bfdc933
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..f31730d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..bd818b5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-mdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index c00c545..0000000
--- a/core/res/res/drawable-mdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..ebdea00
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..41c7ce6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..961a73e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..5903856
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..d38aed2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..87dade3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..ec43047
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..a652117
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..35d1c56
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..264188b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..06ae665
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..a69e301
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..312f76c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..49e0a49
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..8337ffe
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..fb0d0b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index 1443b7f..0000000
--- a/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..f51af63
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..6d87890
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..58f3e0f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..d0d0b1e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..33ec44c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..0166d70
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..a020d64
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..e75ffb8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..1b9fc12
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..f63d47e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..fe005d9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..ea86408
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_solid_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..65b8d4a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_bottom_transparent_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..a397baa
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_bottom_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png
new file mode 100644
index 0000000..469f736
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..b56fa4a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm.9.png
deleted file mode 100644
index e89c9fe..0000000
--- a/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png
new file mode 100644
index 0000000..e8a94dc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_solid_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_solid_qntm_alpha.9.png
new file mode 100644
index 0000000..71b9737
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_solid_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_stacked_transparent_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_qntm_alpha.9.png
new file mode 100644
index 0000000..e2cc715
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ab_stacked_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png
index f220168..605d1de 100644
--- a/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/ab_transparent_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png
new file mode 100644
index 0000000..e1c55ad
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..4b49faf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..561d9ef
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png
new file mode 100644
index 0000000..6fad4a64
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png
new file mode 100644
index 0000000..44d98d5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png
new file mode 100644
index 0000000..c807b50
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png
new file mode 100644
index 0000000..d54f44a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png
new file mode 100644
index 0000000..17c1d99
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png
new file mode 100644
index 0000000..906401e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable/ab_bottom_solid_quantum.xml b/core/res/res/drawable/ab_bottom_solid_quantum.xml
new file mode 100644
index 0000000..848737e
--- /dev/null
+++ b/core/res/res/drawable/ab_bottom_solid_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ab_bottom_solid_qntm_alpha"
+ android:tint="?attr/colorBackground"
+ android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_bottom_transparent_quantum.xml b/core/res/res/drawable/ab_bottom_transparent_quantum.xml
new file mode 100644
index 0000000..29df6b9
--- /dev/null
+++ b/core/res/res/drawable/ab_bottom_transparent_quantum.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ab_bottom_transparent_qntm_alpha"
+ android:tint="?attr/colorBackground"
+ android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_share_pack_quantum.xml b/core/res/res/drawable/ab_share_pack_quantum.xml
new file mode 100644
index 0000000..7d33ff4d
--- /dev/null
+++ b/core/res/res/drawable/ab_share_pack_quantum.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ab_share_pack_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ab_solid_quantum.xml b/core/res/res/drawable/ab_solid_quantum.xml
new file mode 100644
index 0000000..e56bb40
--- /dev/null
+++ b/core/res/res/drawable/ab_solid_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ab_solid_qntm_alpha"
+ android:tint="?attr/colorBackground"
+ android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_solid_shadow_quantum.xml b/core/res/res/drawable/ab_solid_shadow_quantum.xml
new file mode 100644
index 0000000..88e142a
--- /dev/null
+++ b/core/res/res/drawable/ab_solid_shadow_quantum.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ab_solid_shadow_qntm_alpha"
+ android:tint="@color/black" />
diff --git a/core/res/res/drawable/ab_stacked_solid_quantum.xml b/core/res/res/drawable/ab_stacked_solid_quantum.xml
new file mode 100644
index 0000000..df775af
--- /dev/null
+++ b/core/res/res/drawable/ab_stacked_solid_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ab_stacked_solid_qntm_alpha"
+ android:tint="?attr/colorBackground"
+ android:tintMode="multiply" />
diff --git a/core/res/res/drawable/ab_stacked_transparent_quantum.xml b/core/res/res/drawable/ab_stacked_transparent_quantum.xml
new file mode 100644
index 0000000..bdae6b9
--- /dev/null
+++ b/core/res/res/drawable/ab_stacked_transparent_quantum.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ab_stacked_transparent_qntm_alpha"
+ android:tint="?attr/colorBackground"
+ android:tintMode="multiply" />
diff --git a/core/res/res/drawable/btn_cab_done_quantum.xml b/core/res/res/drawable/btn_cab_done_quantum.xml
new file mode 100644
index 0000000..c03ab0a
--- /dev/null
+++ b/core/res/res/drawable/btn_cab_done_quantum.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true">
+ <item android:state_pressed="true">
+ <color android:color="?attr/colorButtonPressed" />
+ </item>
+ <item android:state_focused="true" android:state_enabled="true">
+ <nine-patch android:src="@drawable/btn_cab_done_qntm_alpha"
+ android:tint="?attr/colorButtonPressed" />
+ </item>
+ <item android:state_enabled="true">
+ <nine-patch android:src="@drawable/btn_cab_done_qntm_alpha"
+ android:tint="?attr/colorButtonNormal" />
+ </item>
+</selector>
diff --git a/core/res/res/drawable/ic_media_route_connecting_quantum.xml b/core/res/res/drawable/ic_media_route_connecting_quantum.xml
new file mode 100644
index 0000000..0029dd4
--- /dev/null
+++ b/core/res/res/drawable/ic_media_route_connecting_quantum.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="false">
+ <item android:duration="500">
+ <bitmap android:src="@drawable/ic_media_route_on_0_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:duration="500">
+ <bitmap android:src="@drawable/ic_media_route_on_1_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:duration="500">
+ <bitmap android:src="@drawable/ic_media_route_on_2_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:duration="500">
+ <bitmap android:src="@drawable/ic_media_route_on_1_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+</animation-list>
diff --git a/core/res/res/drawable/ic_media_route_quantum.xml b/core/res/res/drawable/ic_media_route_quantum.xml
new file mode 100644
index 0000000..16b63d4
--- /dev/null
+++ b/core/res/res/drawable/ic_media_route_quantum.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true" android:state_enabled="true"
+ android:drawable="@android:drawable/ic_media_route_connecting_quantum" />
+ <item android:state_activated="true" android:state_enabled="true">
+ <bitmap android:src="@android:drawable/ic_media_route_on_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:state_enabled="true">
+ <bitmap android:src="@android:drawable/ic_media_route_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item>
+ <bitmap android:src="@android:drawable/ic_media_route_disabled_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_empty_quantum.xml b/core/res/res/drawable/ratingbar_full_empty_quantum.xml
new file mode 100644
index 0000000..e5e4315
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_empty_quantum.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item>
+ <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_filled_quantum.xml b/core/res/res/drawable/ratingbar_full_filled_quantum.xml
new file mode 100644
index 0000000..ad3aa5d
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_filled_quantum.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item>
+ <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_quantum.xml b/core/res/res/drawable/ratingbar_full_quantum.xml
new file mode 100644
index 0000000..143e7c2
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_quantum.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@id/background"
+ android:drawable="@drawable/ratingbar_full_empty_quantum" />
+ <item android:id="@id/secondaryProgress"
+ android:drawable="@drawable/ratingbar_full_empty_quantum" />
+ <item android:id="@id/progress"
+ android:drawable="@drawable/ratingbar_full_filled_quantum" />
+</layer-list>
diff --git a/core/res/res/layout/alert_dialog_progress_quantum.xml b/core/res/res/layout/alert_dialog_progress_quantum.xml
new file mode 100644
index 0000000..b9d0814
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_progress_quantum.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+ <ProgressBar android:id="@+id/progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:layout_centerHorizontal="true" />
+ <TextView
+ android:id="@+id/progress_percent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/progress" />
+ <TextView
+ android:id="@+id/progress_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@id/progress" />
+</RelativeLayout>
diff --git a/core/res/res/layout/alert_dialog_quantum.xml b/core/res/res/layout/alert_dialog_quantum.xml
new file mode 100644
index 0000000..4cc76ca
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_quantum.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dip"
+ android:layout_marginEnd="8dip"
+ android:orientation="vertical">
+
+ <LinearLayout android:id="@+id/topPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <View android:id="@+id/titleDividerTop"
+ android:layout_width="match_parent"
+ android:layout_height="2dip"
+ android:visibility="gone"
+ android:background="@android:color/holo_blue_light" />
+ <LinearLayout android:id="@+id/title_template"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical|start"
+ android:minHeight="@dimen/alert_dialog_title_height"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="8dip"
+ android:src="@null" />
+ <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+ style="?android:attr/windowTitleStyle"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart" />
+ </LinearLayout>
+ <View android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="2dip"
+ android:visibility="gone"
+ android:background="@android:color/holo_blue_light" />
+ <!-- If the client uses a customTitle, it will be added here. -->
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/contentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:minHeight="64dp">
+ <ScrollView android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false">
+ <TextView android:id="@+id/message"
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"/>
+ </ScrollView>
+ </LinearLayout>
+
+ <FrameLayout android:id="@+id/customPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:minHeight="64dp">
+ <FrameLayout android:id="@+android:id/custom"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </FrameLayout>
+
+ <LinearLayout android:id="@+id/buttonPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:orientation="vertical"
+ android:dividerPadding="0dip">
+ <LinearLayout
+ style="?android:attr/buttonBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layoutDirection="locale"
+ android:measureWithLargestChild="true">
+ <Button android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_gravity="start"
+ android:layout_weight="1"
+ android:maxLines="2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button3"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1"
+ android:maxLines="2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_gravity="end"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/progress_dialog_quantum.xml b/core/res/res/layout/progress_dialog_quantum.xml
new file mode 100644
index 0000000..84d06b5
--- /dev/null
+++ b/core/res/res/layout/progress_dialog_quantum.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout android:id="@+id/body"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:baselineAligned="false"
+ android:padding="16dip">
+
+ <ProgressBar android:id="@android:id/progress"
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:max="10000"
+ android:layout_marginEnd="16dip" />
+
+ <TextView android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/select_dialog_item_quantum.xml b/core/res/res/layout/select_dialog_item_quantum.xml
new file mode 100644
index 0000000..59b432e
--- /dev/null
+++ b/core/res/res/layout/select_dialog_item_quantum.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+ This layout file is used by the AlertDialog when displaying a list of items.
+ This layout file is inflated and used as the TextView to display individual
+ items.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_multichoice_quantum.xml b/core/res/res/layout/select_dialog_multichoice_quantum.xml
new file mode 100644
index 0000000..8b4c59d
--- /dev/null
+++ b/core/res/res/layout/select_dialog_multichoice_quantum.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+ android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_quantum.xml b/core/res/res/layout/select_dialog_quantum.xml
new file mode 100644
index 0000000..ee04039
--- /dev/null
+++ b/core/res/res/layout/select_dialog_quantum.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+ This layout file is used by the AlertDialog when displaying a list of items.
+ This layout file is inflated and used as the ListView to display the items.
+ Assign an ID so its state will be saved/restored.
+-->
+<view class="com.android.internal.app.AlertController$RecycleListView"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+android:id/select_dialog_listview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:cacheColorHint="@null"
+ android:divider="?android:attr/listDividerAlertDialog"
+ android:scrollbars="vertical"
+ android:overScrollMode="ifContentScrolls"
+ android:textAlignment="viewStart" />
diff --git a/core/res/res/layout/select_dialog_singlechoice_quantum.xml b/core/res/res/layout/select_dialog_singlechoice_quantum.xml
new file mode 100644
index 0000000..27a6648
--- /dev/null
+++ b/core/res/res/layout/select_dialog_singlechoice_quantum.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:checkMark="?android:attr/listChoiceIndicatorSingle"
+ android:ellipsize="marquee" />
diff --git a/core/res/res/layout/tab_indicator_quantum.xml b/core/res/res/layout/tab_indicator_quantum.xml
new file mode 100644
index 0000000..fcb2d5f
--- /dev/null
+++ b/core/res/res/layout/tab_indicator_quantum.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="?android:attr/actionBarSize"
+ android:orientation="horizontal"
+ style="@android:style/Widget.Quantum.Tab">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:visibility="gone" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ style="@android:style/Widget.Quantum.TabText" />
+
+</LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index bd53e49..4d43831 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1677,6 +1677,7 @@
that is, when in portrait. Can be either an absolute dimension
or a fraction of the screen size in that dimension. -->
<attr name="windowFixedHeightMajor" format="dimension|fraction" />
+ <attr name="windowOutsetBottom" format="dimension" />
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -6138,6 +6139,8 @@
<!-- Aspect to use when drawing LockPatternView. Choices are "square"(default), "lock_width"
or "lock_height" -->
<attr name="aspect" format="string" />
+ <!-- Color to use when drawing LockPatternView paths. -->
+ <attr name="pathColor" format="color|reference" />
</declare-styleable>
<!-- Use <code>recognition-service</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 13edf6a..84a1ca4 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -630,8 +630,8 @@
</style>
<style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
- <item name="progressDrawable">@drawable/ratingbar_full_holo_dark</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_dark</item>
+ <item name="progressDrawable">@drawable/ratingbar_full_quantum</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_full_quantum</item>
</style>
<style name="Widget.Quantum.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
@@ -677,7 +677,7 @@
<item name="showDividers">middle</item>
<item name="dividerPadding">8dip</item>
<item name="measureWithLargestChild">true</item>
- <item name="tabLayout">@layout/tab_indicator_holo</item>
+ <item name="tabLayout">@layout/tab_indicator_quantum</item>
</style>
<style name="Widget.Quantum.Tab" parent="Widget.Quantum.ActionBar.TabView">
@@ -731,7 +731,7 @@
</style>
<style name="Widget.Quantum.ActionButton.CloseMode">
- <item name="background">@drawable/btn_cab_done_holo_dark</item>
+ <item name="background">@drawable/btn_cab_done_quantum</item>
</style>
<style name="Widget.Quantum.ActionButton.Overflow">
@@ -768,8 +768,8 @@
<item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
<item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
<item name="background">@drawable/ab_transparent_quantum</item>
- <item name="backgroundStacked">@drawable/ab_stacked_transparent_dark_holo</item>
- <item name="backgroundSplit">@drawable/ab_bottom_transparent_dark_holo</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_transparent_quantum</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_transparent_quantum</item>
<item name="divider">?attr/dividerVertical</item>
<item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
<item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
@@ -780,9 +780,9 @@
<style name="Widget.Quantum.ActionBar.Solid">
<item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
<item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="background">@drawable/ab_solid_dark_holo</item>
- <item name="backgroundStacked">@drawable/ab_stacked_solid_dark_holo</item>
- <item name="backgroundSplit">@drawable/ab_bottom_solid_dark_holo</item>
+ <item name="background">@drawable/ab_solid_quantum</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_solid_quantum</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_solid_quantum</item>
<item name="divider">?attr/dividerVertical</item>
<item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
<item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
@@ -809,7 +809,7 @@
<style name="Widget.Quantum.MediaRouteButton">
<item name="background">?attr/selectableItemBackground</item>
- <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_dark</item>
+ <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_quantum</item>
<item name="minWidth">56dp</item>
<item name="minHeight">48dp</item>
<item name="focusable">true</item>
@@ -896,7 +896,7 @@
<style name="Widget.Quantum.Light.DatePicker" parent="Widget.Quantum.DatePicker"/>
<style name="Widget.Quantum.Light.ActivityChooserView" parent="Widget.Quantum.ActivityChooserView">
- <item name="background">@drawable/ab_share_pack_holo_light</item>
+ <item name="background">@drawable/ab_share_pack_quantum</item>
</style>
<style name="Widget.Quantum.Light.ImageWell" parent="Widget.Quantum.ImageWell"/>
@@ -919,10 +919,7 @@
<style name="Widget.Quantum.Light.ProgressBar.Large.Inverse" parent="Widget.Quantum.ProgressBar.Large.Inverse"/>
<style name="Widget.Quantum.Light.SeekBar" parent="Widget.Quantum.SeekBar"/>
- <style name="Widget.Quantum.Light.RatingBar" parent="Widget.RatingBar">
- <item name="progressDrawable">@drawable/ratingbar_full_holo_light</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_light</item>
- </style>
+ <style name="Widget.Quantum.Light.RatingBar" parent="Widget.Quantum.RatingBar" />
<style name="Widget.Quantum.Light.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
<item name="progressDrawable">@drawable/ratingbar_holo_light</item>
@@ -991,15 +988,15 @@
</style>
<style name="Widget.Quantum.Light.ActionButton.CloseMode">
- <item name="background">@drawable/btn_cab_done_holo_light</item>
+ <item name="background">@drawable/btn_cab_done_quantum</item>
</style>
<style name="Widget.Quantum.Light.ActionBar" parent="Widget.Quantum.ActionBar">
<item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
<item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
<item name="background">@drawable/ab_transparent_quantum</item>
- <item name="backgroundStacked">@drawable/ab_stacked_transparent_light_holo</item>
- <item name="backgroundSplit">@drawable/ab_bottom_transparent_light_holo</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_transparent_quantum</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_transparent_quantum</item>
<item name="homeAsUpIndicator">@drawable/ic_ab_back_quantum</item>
<item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
<item name="indeterminateProgressStyle">@style/Widget.Quantum.Light.ProgressBar</item>
@@ -1008,9 +1005,9 @@
<style name="Widget.Quantum.Light.ActionBar.Solid">
<item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
<item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="background">@drawable/ab_solid_light_holo</item>
- <item name="backgroundStacked">@drawable/ab_stacked_solid_light_holo</item>
- <item name="backgroundSplit">@drawable/ab_bottom_solid_light_holo</item>
+ <item name="background">@drawable/ab_solid_quantum</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_solid_quantum</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_solid_quantum</item>
<item name="divider">?attr/dividerVertical</item>
<item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
<item name="indeterminateProgressStyle">@style/Widget.Quantum.Light.ProgressBar</item>
@@ -1025,7 +1022,7 @@
<style name="Widget.Quantum.Light.FastScroll" parent="Widget.Quantum.FastScroll"/>
<style name="Widget.Quantum.Light.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton">
- <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_light</item>
+ <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_quantum</item>
</style>
<!-- Animation Styles -->
@@ -1047,13 +1044,13 @@
<item name="bottomBright">?attr/colorBackground</item>
<item name="bottomMedium">?attr/colorBackground</item>
<item name="centerMedium">?attr/colorBackground</item>
- <item name="layout">@layout/alert_dialog_holo</item>
- <item name="listLayout">@layout/select_dialog_holo</item>
- <item name="progressLayout">@layout/progress_dialog_holo</item>
- <item name="horizontalProgressLayout">@layout/alert_dialog_progress_holo</item>
- <item name="listItemLayout">@layout/select_dialog_item_holo</item>
- <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_holo</item>
- <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_holo</item>
+ <item name="layout">@layout/alert_dialog_quantum</item>
+ <item name="listLayout">@layout/select_dialog_quantum</item>
+ <item name="progressLayout">@layout/progress_dialog_quantum</item>
+ <item name="horizontalProgressLayout">@layout/alert_dialog_progress_quantum</item>
+ <item name="listItemLayout">@layout/select_dialog_item_quantum</item>
+ <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_quantum</item>
+ <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_quantum</item>
</style>
<style name="AlertDialog.Quantum.Light"/>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index f4a8882..0ce5094 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -38,12 +38,12 @@
to a device’s native theme with all device customizations intact.</p>
<p>For example, when you set your app's {@code targetSdkVersion} to XX or higher, this
theme is applied to your application by default. As such, your app might appear with the
- {@link #Theme_Quantum.Light Quantum.Light} styles on one device, but with a different set of styles on
+ {@link #Theme_Quantum Quantum} styles on one device, but with a different set of styles on
another device. This is great if you want your app to fit with the device's native look and
feel. If, however, you prefer to keep your UI style the same across all devices, you should
- apply a specific theme such as {@link #Theme_Quantum.Light Quantum.Light} or one of your own design.
+ apply a specific theme such as {@link #Theme_Quantum Quantum} or one of your own design.
For more information, read <a
- href="http://android-developers.blogspot.com/20XX/XX/quantum-everywhere.html">Quantum.Light
+ href="http://android-developers.blogspot.com/20XX/XX/quantum-everywhere.html">Quantum
Everywhere</a>.</p>
<p>Styles used by the DeviceDefault theme are named using the convention
Type.DeviceDefault.Etc (for example, {@code Widget.DeviceDefault.Button} and
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 24abd55..d39a1f8 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -476,7 +476,7 @@
<item name="windowFullscreen">false</item>
<item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
- <item name="windowContentOverlay">@drawable/ab_solid_shadow_qntm</item>
+ <item name="windowContentOverlay">@drawable/ab_solid_shadow_quantum</item>
<item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@style/WindowTitle.Quantum</item>
<item name="windowTitleSize">25dip</item>
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 6d29c69..92ecd24 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
<br/>Any versions with less than 0.1% distribution are not shown.</em>
</p>
@@ -92,7 +92,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
<br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
@@ -133,17 +133,17 @@
</tr>
<tr>
<td>2.0</th>
-<td>91.1%</td>
+<td>89.4%</td>
</tr>
<tr>
<td>3.0</th>
-<td>8.8%</td>
+<td>10.5%</td>
</tr>
</table>
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014</em></p>
@@ -161,17 +161,17 @@
var VERSION_DATA =
[
{
- "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A1.2%2C19.0%2C0.1%2C15.2%2C62.0%2C2.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=500x250&cht=p",
+ "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A1.1%2C17.8%2C0.1%2C14.3%2C61.4%2C5.3&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat",
"data": [
{
"api": 8,
"name": "Froyo",
- "perc": "1.2"
+ "perc": "1.1"
},
{
"api": 10,
"name": "Gingerbread",
- "perc": "19.0"
+ "perc": "17.8"
},
{
"api": 13,
@@ -181,27 +181,27 @@
{
"api": 15,
"name": "Ice Cream Sandwich",
- "perc": "15.2"
+ "perc": "14.3"
},
{
"api": 16,
"name": "Jelly Bean",
- "perc": "35.3"
+ "perc": "34.4"
},
{
"api": 17,
"name": "Jelly Bean",
- "perc": "17.1"
+ "perc": "18.1"
},
{
"api": 18,
"name": "Jelly Bean",
- "perc": "9.6"
+ "perc": "8.9"
},
{
"api": 19,
"name": "KitKat",
- "perc": "2.5"
+ "perc": "5.3"
}
]
}
@@ -218,16 +218,15 @@
"Large": {
"hdpi": "0.6",
"ldpi": "0.7",
- "mdpi": "4.3",
+ "mdpi": "4.4",
"tvdpi": "1.5",
"xhdpi": "0.6"
},
"Normal": {
"hdpi": "33.7",
- "ldpi": "0.2",
- "mdpi": "13.6",
- "xhdpi": "19.9",
- "xxhdpi": "11.9"
+ "mdpi": "13.2",
+ "xhdpi": "19.8",
+ "xxhdpi": "12.5"
},
"Small": {
"ldpi": "8.1"
@@ -235,12 +234,12 @@
"Xlarge": {
"hdpi": "0.3",
"ldpi": "0.1",
- "mdpi": "4.3",
- "xhdpi": "0.2"
+ "mdpi": "4.2",
+ "xhdpi": "0.3"
}
},
- "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A9.1%2C22.2%2C1.5%2C34.6%2C20.7%2C11.9&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
- "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.9%2C7.7%2C79.3%2C8.1&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p"
+ "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A8.9%2C21.8%2C1.5%2C34.6%2C20.7%2C12.6&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
+ "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A4.9%2C7.8%2C79.3%2C8.1&chl=Xlarge%7CLarge%7CNormal%7CSmall"
}
];
diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd
index b743b66..2e97d62 100644
--- a/docs/html/google/index.jd
+++ b/docs/html/google/index.jd
@@ -125,7 +125,7 @@
<img src="{@docRoot}images/google/analytics.png" width="40" />
</div>
<h4><a class="external-link"
-href="https://developers.google.com/analytics/devguides/collection/android/v2/"
+href="https://developers.google.com/analytics/devguides/collection/android/v4/"
>Google Analytics</a></h4>
<p>Measure your success and gain insights into how users engage with your app content
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 506cf9d..826dcff 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -11,6 +11,18 @@
<span class="less" style="display:none">show less</span></a></h2>
<ol id="tocIntents" class="hide-nested">
+ <li><a href="#Clock">Alarm Clock</a>
+ <ol>
+ <li><a href="#CreateAlarm">Create an alarm</a></li>
+ <li><a href="#CreateTimer">Create a timer</a></li>
+ <li><a href="#ShowAlarms">Show all alarms</a></li>
+ </ol>
+ </li>
+ <li><a href="#Calendar">Calendar</a>
+ <ol>
+ <li><a href="#AddEvent">Add a calendar event</a></li>
+ </ol>
+ </li>
<li><a href="#Camera">Camera</a>
<ol>
<li><a href="#ImageCapture">Capture a picture or video and return it</a></li>
@@ -116,6 +128,292 @@
+
+
+
+
+<h2 id="Clock">Alarm Clock</h2>
+
+
+<h3 id="CreateAlarm">Create an alarm</h3>
+
+<p>To create a new alarm, use the {@link android.provider.AlarmClock#ACTION_SET_ALARM}
+action and specify alarm details such as the time and message using extras defined below.</p>
+
+<p class="note"><strong>Note:</strong> Only the hour, minutes, and message extras are available
+since Android 2.3 (API level 9). The other extras were added in later versions of the platform.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SET_ALARM}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+ <dl>
+ <dt>{@link android.provider.AlarmClock#EXTRA_HOUR}</dt>
+ <dd>The hour for the alarm.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_MINUTES}</dt>
+ <dd>The minutes for the alarm.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_MESSAGE}</dt>
+ <dd>A custom message to identify the alarm.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_DAYS}</dt>
+ <dd>An {@link java.util.ArrayList} including each week day on which this alarm should
+ be repeated. Each day must be declared with an integer from the {@link java.util.Calendar}
+ class such as {@link java.util.Calendar#MONDAY}.
+ <p>For a one-time alarm, do not specify this extra.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_RINGTONE}</dt>
+ <dd>A {@code content:} URI specifying a ringtone to use with the alarm, or {@link
+ android.provider.AlarmClock#VALUE_RINGTONE_SILENT} for no ringtone.
+ <p>To use the default ringtone, do not specify this extra.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_VIBRATE}</dt>
+ <dd>A boolean specifying whether to vibrate for this alarm.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_SKIP_UI}</dt>
+ <dd>A boolean specifying whether the responding app should skip its UI when setting the alarm.
+ If true, the app should bypass any confirmation UI and simply set the specified alarm.</dd>
+ </dl>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void createAlarm(String message, int hour, int minutes) {
+ Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)
+ .putExtra(AlarmClock.EXTRA_MESSAGE, message)
+ .putExtra(AlarmClock.EXTRA_HOUR, hour)
+ .putExtra(AlarmClock.EXTRA_MINUTES, minutes);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<div class="note"><strong>Note:</strong>
+<p>In order to invoke the {@link
+android.provider.AlarmClock#ACTION_SET_ALARM} intent, your app must have the
+{@link android.Manifest.permission#SET_ALARM} permission:</p>
+<pre>
+<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+</pre>
+</div>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+<activity ...>
+ <intent-filter>
+ <action android:name="android.intent.action.SET_ALARM" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+</activity>
+</pre>
+
+
+
+<h3 id="CreateTimer">Create a timer</h3>
+
+<p>To create a countdown timer, use the {@link android.provider.AlarmClock#ACTION_SET_TIMER}
+action and specify timer details such as the duration using extras defined below.</p>
+
+<p class="note"><strong>Note:</strong> This intent was added
+in Android 4.4 (API level 19).</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SET_TIMER}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+ <dl>
+ <dt>{@link android.provider.AlarmClock#EXTRA_LENGTH}</dt>
+ <dd>The length of the timer in seconds.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_MESSAGE}</dt>
+ <dd>A custom message to identify the timer.</dd>
+ <dt>{@link android.provider.AlarmClock#EXTRA_SKIP_UI}</dt>
+ <dd>A boolean specifying whether the responding app should skip its UI when setting the timer.
+ If true, the app should bypass any confirmation UI and simply start the specified timer.</dd>
+ </dl>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void startTimer(String message, int seconds) {
+ Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)
+ .putExtra(AlarmClock.EXTRA_MESSAGE, message)
+ .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
+ .putExtra(AlarmClock.EXTRA_SKIP_UI, true);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<div class="note"><strong>Note:</strong>
+<p>In order to invoke the {@link
+android.provider.AlarmClock#ACTION_SET_TIMER} intent, your app must have the
+{@link android.Manifest.permission#SET_ALARM} permission:</p>
+<pre>
+<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+</pre>
+</div>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+<activity ...>
+ <intent-filter>
+ <action android:name="android.intent.action.SET_TIMER" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+</activity>
+</pre>
+
+
+
+
+
+<h3 id="ShowAlarms">Show all alarms</h3>
+
+<p>To show the list of alarms, use the {@link android.provider.AlarmClock#ACTION_SHOW_ALARMS}
+action.</p>
+
+<p>Although not many apps will invoke this intent (it's primarily used by system apps),
+any app that behaves as an alarm clock should implement
+this intent filter and respond by showing the list of current alarms.</p>
+
+<p class="note"><strong>Note:</strong> This intent was added
+in Android 4.4 (API level 19).</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SHOW_ALARMS}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+</dl>
+
+<p><b>Example intent filter:</b></p>
+<pre>
+<activity ...>
+ <intent-filter>
+ <action android:name="android.intent.action.SHOW_ALARMS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+</activity>
+</pre>
+
+
+
+
+
+
+<h2 id="Calendar">Calendar</h2>
+
+
+<h3 id="AddEvent">Add a calendar event</h3>
+
+<p>To add a new event to the user's calendar, use the {@link android.content.Intent#ACTION_INSERT}
+action and specify the data URI with {@link android.provider.CalendarContract.Events#CONTENT_URI
+Events.CONTENT_URI}. You can then specify various event details using extras defined below.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_INSERT}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>{@link android.provider.CalendarContract.Events#CONTENT_URI
+Events.CONTENT_URI}</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>{@code "vnd.android.cursor.dir/event"}
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+ <dl>
+ <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY}</dt>
+ <dd>A boolean specifying whether this is an all-day event.</dd>
+ <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME}</dt>
+ <dd>The start time of the event (milliseconds since epoch).</dd>
+ <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME}</dt>
+ <dd>The end time of the event (milliseconds since epoch).</dd>
+ <dt>{@link android.provider.CalendarContract.EventsColumns#TITLE}</dt>
+ <dd>The event title.</dd>
+ <dt>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</dt>
+ <dd>The event description.</dd>
+ <dt>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</dt>
+ <dd>The event location.</dd>
+ <dt>{@link android.content.Intent#EXTRA_EMAIL}</dt>
+ <dd>A comma-separated list of email addresses that specify the invitees.</dd>
+ </dl>
+ <p>Many more event details can be specified using the constants defined in the
+ {@link android.provider.CalendarContract.EventsColumns} class.</p>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void addEvent(String title, String location, Calendar begin, Calendar end) {
+ Intent intent = new Intent(Intent.ACTION_INSERT)
+ .setData(Events.CONTENT_URI)
+ .putExtra(Events.TITLE, title)
+ .putExtra(Events.EVENT_LOCATION, location)
+ .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, begin)
+ .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+<activity ...>
+ <intent-filter>
+ <action android:name="android.intent.action.INSERT" />
+ <data android:mimeType="vnd.android.cursor.dir/event" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+</activity>
+</pre>
+
+
+
+
+
+
+
+
+
+
+
+
+
<h2 id="Camera">Camera</h2>
@@ -211,6 +509,7 @@
+
<h2 id="Contacts">Contacts/People App</h2>
@@ -427,7 +726,7 @@
<dd>The type is inferred from contact URI.
</dd>
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
<dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}
so you can populate fields of the contact details.
</dd>
@@ -469,7 +768,7 @@
<dt><b>MIME Type</b></dt>
<dd>{@link android.provider.ContactsContract.Contacts#CONTENT_TYPE Contacts.CONTENT_TYPE}</dd>
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
<dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}.
</dd>
</dl>
@@ -523,7 +822,7 @@
</dl>
</dd>
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
<dd>
<dl>
<dt>{@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</dt>
@@ -648,7 +947,7 @@
<dd>The MIME type corresponding to the file type the user should select.
</dd>
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
<dd>
<dl>
<dt>{@link android.content.Intent#EXTRA_ALLOW_MULTIPLE}
@@ -768,7 +1067,7 @@
<dd>The MIME type corresponding to the file type the user should select.
</dd>
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
<dd>
<dl>
<dt>{@link android.content.Intent#EXTRA_MIME_TYPES}
@@ -1139,7 +1438,7 @@
</dl>
</dd>
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
<dd>
<dl>
<dt><code>"subject"</code></dt>
diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd
index 41ad5de..8674134 100644
--- a/docs/html/sdk/installing/studio-build.jd
+++ b/docs/html/sdk/installing/studio-build.jd
@@ -1,4 +1,4 @@
-page.title=Building your Project
+page.title=Building Your Project with Gradle
@jd:body
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 0e543e4..c281644 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -37,7 +37,7 @@
<li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
Using the Layout Editor</a></li>
<li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
- Building your Project</a></li>
+ Building Your Project with Gradle</a></li>
</ul>
</li>
<li><a href="<?cs var:toroot ?>sdk/exploring.html">
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 50485db..c4cb362 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -10,9 +10,9 @@
<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
+<div id="tb-wrapper">
+<div id="tb">
+
<h2>This lesson teaches you to</h2>
<ol>
@@ -27,10 +27,10 @@
SDK</a></li>
<li><a href="{@docRoot}tools/projects/index.html">Managing Projects</a></li>
</ul>
-
-
-</div>
-</div>
+
+
+</div>
+</div>
<p>An Android project contains all the files that comprise the source code for your Android
app. The Android SDK tools make it easy to start a new Android project with a set of
@@ -42,7 +42,7 @@
<p class="note"><strong>Note:</strong> You should already have the Android SDK installed, and if
you're using Eclipse, you should also have the <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
-plugin</a> installed (version 21.0.0 or higher). If you don't have these, follow the guide to <a
+plugin</a> installed (version 22.6.2 or higher). If you don't have these, follow the guide to <a
href="{@docRoot}sdk/installing/index.html">Installing the Android SDK</a> before you start this
lesson.</p>
@@ -50,7 +50,7 @@
<h2 id="Eclipse">Create a Project with Eclipse</h2>
<ol>
- <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
+ <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
<li>In the window that appears, open the <strong>Android</strong> folder,
select <strong>Android Application Project</strong>, and click <strong>Next</strong>.</li>
@@ -116,11 +116,11 @@
<li>Now you can select an activity template from which to begin building your app.
<p>For this project, select <strong>BlankActivity</strong> and click <strong>Next</strong>.</p>
</li>
- <li>Leave all the details for the activity in their default state and click
+ <li>Leave all the details for the activity in their default state and click
<strong>Finish</strong>.</li>
</ol>
-<p>Your Android project is now a basic "Hello World" app that contains some default files.
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
@@ -155,7 +155,7 @@
projects.</p></li>
</ol>
-<p>Your Android project is now a basic "Hello World" app that contains some default files.
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
<p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the
diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd
index 4c1a0dc3..1b49096 100644
--- a/docs/html/training/basics/firstapp/index.jd
+++ b/docs/html/training/basics/firstapp/index.jd
@@ -8,21 +8,21 @@
@jd:body
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>Dependencies and prerequisites</h2>
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
<ul>
<li><a href="http://developer.android.com/sdk/index.html">Android SDK</a></li>
- <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 20.0.0 or higher
+ <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 22.6.2 or higher
(if you're using Eclipse)</li>
</ul>
-
-</div>
-</div>
-
-<p>Welcome to Android application development!</p>
+
+</div>
+</div>
+
+<p>Welcome to Android application development!</p>
<p>This class teaches you how to build your first Android app. You’ll learn how to create an Android
project and run a debuggable version of the app. You'll also learn some fundamentals of Android app
@@ -36,6 +36,10 @@
<li>Download the latest SDK tools and platforms using the SDK Manager.</li>
</ol>
+<p class="note"><strong>Note:</strong> Make sure you install the most recent versions of the ADT
+plugin and the Android SDK before you start this class. The procedures described in this class may
+not apply to earlier versions.</p>
+
<p>If you haven't already done these tasks, start by downloading the
<a href="{@docRoot}sdk/index.html">Android SDK</a> and following the install steps.
Once you've finished the setup, you're ready to begin this class.</p>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 9aa25a3..27d2c10 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -10,9 +10,9 @@
<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
+<div id="tb-wrapper">
+<div id="tb">
+
<h2>This lesson teaches you to</h2>
<ol>
@@ -30,10 +30,10 @@
<li><a href="{@docRoot}sdk/installing/index.html">Installing the
SDK</a></li>
</ul>
-
-
-</div>
-</div>
+
+
+</div>
+</div>
@@ -151,7 +151,7 @@
</pre>
<p class="note"><strong>Note:</strong>
-You now need an import statement for <code>android.widget.EditText</code>.
+You now need an import statement for <code>android.widget.EditText</code>.
You'll define the <code>EXTRA_MESSAGE</code> constant in a moment.</p>
<p>An {@link android.content.Intent} can carry a collection of various data types as key-value
@@ -212,7 +212,7 @@
<p>To create a new activity using Eclipse:</p>
<ol>
- <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
+ <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
<li>In the window that appears, open the <strong>Android</strong> folder
and select <strong>Android Activity</strong>. Click <strong>Next</strong>.</li>
@@ -247,15 +247,19 @@
<li>There's also an implementation of {@link android.app.Activity#onOptionsItemSelected
onOptionsItemSelected()} which handles the behavior for the action bar's <em>Up</em> behavior.
Keep this one the way it is.</li>
- <li>There's also a <code>PlaceholderFragment</code> class that extends
+ <li>There's also a <code>PlaceholderFragment</code> class that extends
{@link android.app.Fragment}. You will not need this class in the final version of this
activity.</li>
</ul>
-<p>Fragments decompose application functionality and UI into reusable modules. For more
-information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments
+<p>Fragments decompose application functionality and UI into reusable modules. For more
+information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments
API Guide</a>. The final version of this activity does not use fragments.</p>
+<p class="note"><strong>Note:</strong> Your activity may look different if you did not use
+the latest version of the ADT plugin. Make sure you install the latest version of the
+<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT plugin</a> to complete this tutorial.</p>
+
<p>The {@code DisplayMessageActivity} class should now look like this:</p>
<pre>
diff --git a/docs/html/wear/images/laptop-bridge.png b/docs/html/wear/images/laptop-bridge.png
index b481224..083b82b 100644
--- a/docs/html/wear/images/laptop-bridge.png
+++ b/docs/html/wear/images/laptop-bridge.png
Binary files differ
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 7f1c5c7..4bd5a80 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) ||
@@ -4083,18 +4086,31 @@
} else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
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);
+
+ //TODO(pmclean) - Ignore for now the hasPlayback & hasCapture flags since we
+ // still need to call setWiredDeviceConnectionState() on disconnect (when we
+ // don't have card/device files to parse for this info). We will need to store
+ // that info here when we get smarter about multiple USB card/devices.
+ // Playback Device
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);
setWiredDeviceConnectionState(device, state, params);
- } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
+
+ // Capture Device
+ device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
+ AudioSystem.DEVICE_IN_USB_ACCESSORY : 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;
synchronized (mScoClients) {
@@ -4199,7 +4215,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/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 40c6797..57bc171 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1321,7 +1321,7 @@
*
* @param level send level scalar
* @return error code or success, see {@link #SUCCESS},
- * {@link #ERROR_INVALID_OPERATION}
+ * {@link #ERROR_INVALID_OPERATION}, {@link #ERROR}
*/
public int setAuxEffectSendLevel(float level) {
if (isRestricted()) {
@@ -1337,8 +1337,8 @@
if (level > getMaxVolume()) {
level = getMaxVolume();
}
- native_setAuxEffectSendLevel(level);
- return SUCCESS;
+ int err = native_setAuxEffectSendLevel(level);
+ return err == 0 ? SUCCESS : ERROR;
}
//---------------------------------------------------------
@@ -1508,7 +1508,7 @@
int sampleRateInHz, int channelConfig, int audioFormat);
private native final int native_attachAuxEffect(int effectId);
- private native final void native_setAuxEffectSendLevel(float level);
+ private native final int native_setAuxEffectSendLevel(float level);
//---------------------------------------------------------
// Utility methods
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 7170ffb..c016d08 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,11 +20,14 @@
import java.util.UUID;
import java.util.HashMap;
import java.util.List;
+import android.os.Binder;
+import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.util.Log;
+import android.content.Context;
/**
* MediaDrm can be used to obtain keys for decrypting protected media streams, in
@@ -101,6 +104,20 @@
private long mNativeContext;
/**
+ * Specify no certificate type
+ *
+ * @hide - not part of the public API at this time
+ */
+ public static final int CERTIFICATE_TYPE_NONE = 0;
+
+ /**
+ * Specify X.509 certificate type
+ *
+ * @hide - not part of the public API at this time
+ */
+ public static final int CERTIFICATE_TYPE_X509 = 1;
+
+ /**
* Query if the given scheme identified by its UUID is supported on
* this device.
* @param uuid The UUID of the crypto scheme.
@@ -316,6 +333,9 @@
* Contains the opaque data an app uses to request keys from a license server
*/
public final static class KeyRequest {
+ private byte[] mData;
+ private String mDefaultUrl;
+
KeyRequest() {}
/**
@@ -329,9 +349,6 @@
* server URL from other sources.
*/
public String getDefaultUrl() { return mDefaultUrl; }
-
- private byte[] mData;
- private String mDefaultUrl;
};
/**
@@ -456,7 +473,12 @@
* is returned in ProvisionRequest.data. The recommended URL to deliver the provision
* request to is returned in ProvisionRequest.defaultUrl.
*/
- public native ProvisionRequest getProvisionRequest();
+ public ProvisionRequest getProvisionRequest() {
+ return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, "");
+ }
+
+ private native ProvisionRequest getProvisionRequestNative(int certType,
+ String certAuthority);
/**
* After a provision response is received by the app, it is provided to the DRM
@@ -468,7 +490,12 @@
* @throws DeniedByServerException if the response indicates that the
* server rejected the request
*/
- public native void provideProvisionResponse(byte[] response)
+ public void provideProvisionResponse(byte[] response)
+ throws DeniedByServerException {
+ provideProvisionResponseNative(response);
+ }
+
+ private native Certificate provideProvisionResponseNative(byte[] response)
throws DeniedByServerException;
/**
@@ -683,6 +710,120 @@
return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
}
+ /**
+ * Contains the opaque data an app uses to request a certificate from a provisioning
+ * server
+ *
+ * @hide - not part of the public API at this time
+ */
+ public final static class CertificateRequest {
+ private byte[] mData;
+ private String mDefaultUrl;
+
+ CertificateRequest(byte[] data, String defaultUrl) {
+ mData = data;
+ mDefaultUrl = defaultUrl;
+ }
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() { return mData; }
+
+ /**
+ * Get the default URL to use when sending the certificate request
+ * message to a server, if known. The app may prefer to use a different
+ * certificate server URL obtained from other sources.
+ */
+ public String getDefaultUrl() { return mDefaultUrl; }
+ }
+
+ /**
+ * Generate a certificate request, specifying the certificate type
+ * and authority. The response received should be passed to
+ * provideCertificateResponse.
+ *
+ * @param certType Specifies the certificate type.
+ *
+ * @param certAuthority is passed to the certificate server to specify
+ * the chain of authority.
+ *
+ * @hide - not part of the public API at this time
+ */
+ public CertificateRequest getCertificateRequest(int certType,
+ String certAuthority)
+ {
+ ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority);
+ return new CertificateRequest(provisionRequest.getData(),
+ provisionRequest.getDefaultUrl());
+ }
+
+ /**
+ * Contains the wrapped private key and public certificate data associated
+ * with a certificate.
+ *
+ * @hide - not part of the public API at this time
+ */
+ public final static class Certificate {
+ Certificate() {}
+
+ /**
+ * Get the wrapped private key data
+ */
+ public byte[] getWrappedPrivateKey() { return mWrappedKey; }
+
+ /**
+ * Get the PEM-encoded certificate chain
+ */
+ public byte[] getContent() { return mCertificateData; }
+
+ private byte[] mWrappedKey;
+ private byte[] mCertificateData;
+ }
+
+
+ /**
+ * Process a response from the certificate server. The response
+ * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+ * <p>
+ * The public X509 certificate chain and wrapped private key are returned
+ * in the returned Certificate objec. The certificate chain is in PEM format.
+ * The wrapped private key should be stored in application private
+ * storage, and used when invoking the signRSA method.
+ *
+ * @param response the opaque certificate response byte array to provide to the
+ * DRM engine plugin.
+ *
+ * @throws DeniedByServerException if the response indicates that the
+ * server rejected the request
+ *
+ * @hide - not part of the public API at this time
+ */
+ public Certificate provideCertificateResponse(byte[] response)
+ throws DeniedByServerException {
+ return provideProvisionResponseNative(response);
+ }
+
+ private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId,
+ String algorithm, byte[] wrappedKey,
+ byte[] message);
+
+ /**
+ * Sign data using an RSA key
+ *
+ * @param context the app context
+ * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+ * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+ * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+ * from provideCertificateResponse
+ * @param message the data for which a signature is to be computed
+ *
+ * @hide - not part of the public API at this time
+ */
+ public byte[] signRSA(Context context, byte[] sessionId, String algorithm, byte[] wrappedKey, byte[] message) {
+ return signRSANative(this, sessionId, algorithm, wrappedKey, message);
+ }
+
@Override
protected void finalize() {
native_finalize();
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index b2fb2df..d04b1f8 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -27,6 +27,8 @@
#include "jni.h"
#include "JNIHelp.h"
+#include <cutils/compiler.h>
+
#include <gui/Surface.h>
#include <media/ICrypto.h>
@@ -738,6 +740,10 @@
} else if (numBytesOfClearDataObj != NULL
&& env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
err = -ERANGE;
+ // subSamples array may silently overflow if number of samples are too large. Use
+ // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
+ } else if ( CC_UNLIKELY(numSubSamples >= INT32_MAX / sizeof(*subSamples)) ) {
+ err = -EINVAL;
} else {
jboolean isCopy;
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 052d97d..1dbaa3a 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -100,6 +100,16 @@
jint kKeyTypeRelease;
} gKeyTypes;
+struct CertificateTypes {
+ jint kCertificateTypeNone;
+ jint kCertificateTypeX509;
+} gCertificateTypes;
+
+struct CertificateFields {
+ jfieldID wrappedPrivateKey;
+ jfieldID certificateData;
+};
+
struct fields_t {
jfieldID context;
jmethodID post_event;
@@ -110,6 +120,11 @@
SetFields set;
IteratorFields iterator;
EntryFields entry;
+ CertificateFields certificate;
+ jclass certificateClassId;
+ jclass hashmapClassId;
+ jclass arraylistClassId;
+ jclass stringClassId;
};
static fields_t gFields;
@@ -406,8 +421,7 @@
*/
static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
- jclass clazz;
- FIND_CLASS(clazz, "java/lang/String");
+ jclass clazz = gFields.stringClassId;
KeyedVector<String8, String8> keyedVector;
jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
@@ -450,8 +464,7 @@
}
static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
- jclass clazz;
- FIND_CLASS(clazz, "java/util/HashMap");
+ jclass clazz = gFields.hashmapClassId;
jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
for (size_t i = 0; i < map.size(); ++i) {
jstring jkey = env->NewStringUTF(map.keyAt(i).string());
@@ -465,8 +478,7 @@
static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
List<Vector<uint8_t> > list) {
- jclass clazz;
- FIND_CLASS(clazz, "java/util/ArrayList");
+ jclass clazz = gFields.arraylistClassId;
jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
List<Vector<uint8_t> >::iterator iter = list.begin();
while (iter != list.end()) {
@@ -542,6 +554,11 @@
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
+ gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
+ gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
+
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
@@ -550,6 +567,11 @@
GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
+ FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
+ GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
+ GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
+ gFields.certificateClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
FIND_CLASS(clazz, "java/util/ArrayList");
GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
@@ -571,6 +593,15 @@
FIND_CLASS(clazz, "java/util/Map$Entry");
GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
+
+ FIND_CLASS(clazz, "java/util/HashMap");
+ gFields.hashmapClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
+ FIND_CLASS(clazz, "java/lang/String");
+ gFields.stringClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
+ FIND_CLASS(clazz, "java/util/ArrayList");
+ gFields.arraylistClassId = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
}
static void android_media_MediaDrm_native_setup(
@@ -826,8 +857,8 @@
return KeyedVectorToHashMap(env, infoMap);
}
-static jobject android_media_MediaDrm_getProvisionRequest(
- JNIEnv *env, jobject thiz) {
+static jobject android_media_MediaDrm_getProvisionRequestNative(
+ JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
@@ -839,7 +870,17 @@
Vector<uint8_t> request;
String8 defaultUrl;
- status_t err = drm->getProvisionRequest(request, defaultUrl);
+ String8 certType;
+ if (jcertType == gCertificateTypes.kCertificateTypeX509) {
+ certType = "X.509";
+ } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
+ certType = "none";
+ } else {
+ certType = "invalid";
+ }
+
+ String8 certAuthority = JStringToString8(env, jcertAuthority);
+ status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
return NULL;
@@ -863,27 +904,43 @@
return provisionObj;
}
-static void android_media_MediaDrm_provideProvisionResponse(
+static jobject android_media_MediaDrm_provideProvisionResponseNative(
JNIEnv *env, jobject thiz, jbyteArray jresponse) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
- return;
+ return NULL;
}
if (jresponse == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"provision response is null");
- return;
+ return NULL;
}
Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+ Vector<uint8_t> certificate, wrappedKey;
- status_t err = drm->provideProvisionResponse(response);
+ status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
+
+ // Fill out return obj
+ jclass clazz = gFields.certificateClassId;
+
+ jobject certificateObj = NULL;
+
+ if (clazz && certificate.size() && wrappedKey.size()) {
+ certificateObj = env->AllocObject(clazz);
+ jbyteArray jcertificate = VectorToJByteArray(env, certificate);
+ env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
+
+ jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
+ env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
+ }
throwExceptionAsNecessary(env, err, "Failed to handle provision response");
+ return certificateObj;
}
static jobject android_media_MediaDrm_getSecureStops(
@@ -1209,6 +1266,38 @@
}
+static jbyteArray android_media_MediaDrm_signRSANative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return NULL;
+ }
+
+ if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "required argument is null");
+ return NULL;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ String8 algorithm = JStringToString8(env, jalgorithm);
+ Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
+ Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+ Vector<uint8_t> signature;
+
+ status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
+ return NULL;
+ }
+
+ return VectorToJByteArray(env, signature);
+}
+
+
static JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaDrm_release },
{ "native_init", "()V", (void *)android_media_MediaDrm_native_init },
@@ -1244,11 +1333,11 @@
{ "queryKeyStatus", "([B)Ljava/util/HashMap;",
(void *)android_media_MediaDrm_queryKeyStatus },
- { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
- (void *)android_media_MediaDrm_getProvisionRequest },
+ { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
+ (void *)android_media_MediaDrm_getProvisionRequestNative },
- { "provideProvisionResponse", "([B)V",
- (void *)android_media_MediaDrm_provideProvisionResponse },
+ { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
+ (void *)android_media_MediaDrm_provideProvisionResponseNative },
{ "getSecureStops", "()Ljava/util/List;",
(void *)android_media_MediaDrm_getSecureStops },
@@ -1287,6 +1376,9 @@
{ "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
(void *)android_media_MediaDrm_verifyNative },
+
+ { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
+ (void *)android_media_MediaDrm_signRSANative },
};
int register_android_media_Drm(JNIEnv *env) {
diff --git a/media/lib/Android.mk b/media/lib/remotedisplay/Android.mk
similarity index 93%
rename from media/lib/Android.mk
rename to media/lib/remotedisplay/Android.mk
index 50799a6..ea1ac2b 100644
--- a/media/lib/Android.mk
+++ b/media/lib/remotedisplay/Android.mk
@@ -15,7 +15,7 @@
#
LOCAL_PATH := $(call my-dir)
-# the library
+# the remotedisplay library
# ============================================================
include $(CLEAR_VARS)
@@ -23,7 +23,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- $(call all-subdir-java-files) \
+ $(call all-java-files-under, java) \
$(call all-aidl-files-under, java)
include $(BUILD_JAVA_LIBRARY)
diff --git a/media/lib/README.txt b/media/lib/remotedisplay/README.txt
similarity index 99%
rename from media/lib/README.txt
rename to media/lib/remotedisplay/README.txt
index cade3df..5738dbe 100644
--- a/media/lib/README.txt
+++ b/media/lib/remotedisplay/README.txt
@@ -25,4 +25,3 @@
library is a compromise to make new capabilities available to the system
without exposing the full surface area of the support library media
route provider protocol.
-
diff --git a/media/lib/com.android.media.remotedisplay.xml b/media/lib/remotedisplay/com.android.media.remotedisplay.xml
similarity index 100%
rename from media/lib/com.android.media.remotedisplay.xml
rename to media/lib/remotedisplay/com.android.media.remotedisplay.xml
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
diff --git a/media/lib/Android.mk b/media/lib/signer/Android.mk
similarity index 76%
copy from media/lib/Android.mk
copy to media/lib/signer/Android.mk
index 50799a6..4c3772f 100644
--- a/media/lib/Android.mk
+++ b/media/lib/signer/Android.mk
@@ -15,24 +15,23 @@
#
LOCAL_PATH := $(call my-dir)
-# the library
+# the mediadrm signer library
# ============================================================
include $(CLEAR_VARS)
-LOCAL_MODULE:= com.android.media.remotedisplay
+LOCAL_MODULE:= com.android.mediadrm.signer
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- $(call all-subdir-java-files) \
- $(call all-aidl-files-under, java)
+ $(call all-java-files-under, java)
-include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_STATIC_JAVA_LIBRARY)
-# ==== com.android.media.remotedisplay.xml lib def ========================
+# ==== com.android.mediadrm.signer.xml lib def ========================
include $(CLEAR_VARS)
-LOCAL_MODULE := com.android.media.remotedisplay.xml
+LOCAL_MODULE := com.android.mediadrm.signer.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
diff --git a/media/lib/signer/README.txt b/media/lib/signer/README.txt
new file mode 100644
index 0000000..362ab8e
--- /dev/null
+++ b/media/lib/signer/README.txt
@@ -0,0 +1,28 @@
+This library (com.android.mediadrm.signer.jar) is a shared java library
+containing classes required by unbundled apps running on devices that use
+the certficate provisioning and private key signing capabilities provided
+by the MediaDrm API.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled CAST receivers
+ that may be distributed outside the system image. So it MUST BE API STABLE.
+ You can add but not remove. The rules are the same as for the
+ public platform SDK API.
+o This library can see and instantiate internal platform classes, but it must not
+ expose them in any public method (or by extending them via inheritance). This would
+ break clients of the library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exist? ---
+
+Unbundled apps cannot use internal platform classes.
+
+This library will eventually be replaced when the provisioned certificate-
+based signing infrastructure that is currently defined in the support library
+is reintegrated with the framework in a new API. That API isn't ready yet so
+this library is a compromise to make new capabilities available to the system
+without exposing the full surface area of the support library.
+
diff --git a/media/lib/signer/com.android.mediadrm.signer.xml b/media/lib/signer/com.android.mediadrm.signer.xml
new file mode 100644
index 0000000..b5b1f09
--- /dev/null
+++ b/media/lib/signer/com.android.mediadrm.signer.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<permissions>
+ <library name="com.android.media.drm.signer"
+ file="/system/framework/com.android.media.drm.signer.jar" />
+</permissions>
diff --git a/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
new file mode 100644
index 0000000..d971afb
--- /dev/null
+++ b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2013 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.mediadrm.signer;
+
+import android.content.Context;
+import android.media.MediaDrm;
+import android.media.DeniedByServerException;
+
+/**
+ * Provides certificate request generation, response handling and
+ * signing APIs
+ */
+public final class MediaDrmSigner {
+ private MediaDrmSigner() {}
+
+ /**
+ * Specify X.509 certificate type
+ */
+ public static final int CERTIFICATE_TYPE_X509 = MediaDrm.CERTIFICATE_TYPE_X509;
+
+ /**
+ * Contains the opaque data an app uses to request a certificate from a provisioning
+ * server
+ */
+ public final static class CertificateRequest {
+ private MediaDrm.CertificateRequest mCertRequest;
+
+ CertificateRequest(MediaDrm.CertificateRequest certRequest) {
+ mCertRequest = certRequest;
+ }
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() {
+ return mCertRequest.getData();
+ }
+
+ /**
+ * Get the default URL to use when sending the certificate request
+ * message to a server, if known. The app may prefer to use a different
+ * certificate server URL obtained from other sources.
+ */
+ public String getDefaultUrl() {
+ return mCertRequest.getDefaultUrl();
+ }
+ }
+
+ /**
+ * Contains the wrapped private key and public certificate data associated
+ * with a certificate.
+ */
+ public final static class Certificate {
+ private MediaDrm.Certificate mCertificate;
+
+ Certificate(MediaDrm.Certificate certificate) {
+ mCertificate = certificate;
+ }
+
+ /**
+ * Get the wrapped private key data
+ */
+ public byte[] getWrappedPrivateKey() {
+ return mCertificate.getWrappedPrivateKey();
+ }
+
+ /**
+ * Get the PEM-encoded public certificate chain
+ */
+ public byte[] getContent() {
+ return mCertificate.getContent();
+ }
+ }
+
+ /**
+ * Generate a certificate request, specifying the certificate type
+ * and authority. The response received should be passed to
+ * provideCertificateResponse.
+ *
+ * @param drm the MediaDrm object
+ * @param certType Specifies the certificate type.
+ * @param certAuthority is passed to the certificate server to specify
+ * the chain of authority.
+ */
+ public static CertificateRequest getCertificateRequest(MediaDrm drm, int certType,
+ String certAuthority) {
+ return new CertificateRequest(drm.getCertificateRequest(certType, certAuthority));
+ }
+
+ /**
+ * Process a response from the provisioning server. The response
+ * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+ *
+ * The public X509 certificate chain and wrapped private key are returned
+ * in the returned Certificate objec. The certificate chain is in BIO serialized
+ * PEM format. The wrapped private key should be stored in application private
+ * storage, and used when invoking the signRSA method.
+ *
+ * @param drm the MediaDrm object
+ * @param response the opaque certificate response byte array to provide to the
+ * DRM engine plugin.
+ * @throws android.media.DeniedByServerException if the response indicates that the
+ * server rejected the request
+ */
+ public static Certificate provideCertificateResponse(MediaDrm drm, byte[] response)
+ throws DeniedByServerException {
+ return new Certificate(drm.provideCertificateResponse(response));
+ }
+
+ /**
+ * Sign data using an RSA key
+ *
+ * @param context the App context
+ * @param drm the MediaDrm object
+ * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+ * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+ * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+ * from provideCertificateResponse
+ * @param message the data for which a signature is to be computed
+ */
+ public static byte[] signRSA(Context context, MediaDrm drm, byte[] sessionId,
+ String algorithm, byte[] wrappedKey, byte[] message) {
+ return drm.signRSA(context, sessionId, algorithm, wrappedKey, message);
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 43ebef4..5f3ba74 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -140,7 +140,9 @@
private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
int requestId = mCameraUser.submitRequest(request, streaming);
- assertTrue("Request IDs should be non-negative", requestId >= 0);
+ assertTrue(
+ "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
+ requestId >= 0);
return requestId;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 3f17aa9..26498ca 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -309,7 +309,7 @@
});
// rational (n) -- in particular rational x 9
- checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
+ checkKeyGetAndSetArray("android.sensor.calibrationTransform", Rational[].class,
new Rational[] {
new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index c3aa47f..354d13f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -981,6 +981,13 @@
return;
}
+ if (mLockPatternUtils.checkVoldPassword()) {
+ if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
+ // Without this, settings is not enabled until the lock screen first appears
+ hideLocked();
+ return;
+ }
+
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked(options);
}
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f6e875c..f5ce222 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -26,7 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
- android:background="#88000000">
+ android:background="#e6444444">
<ImageView
android:id="@+id/activity_icon"
android:layout_width="@dimen/recents_task_view_icon_size"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a9b69854..38e1083 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -248,6 +248,6 @@
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">2dp</dimen>
- <!-- Width of the zen mode interstitial dialog. Defaults to MATCH_PARENT. -->
- <dimen name="zen_mode_dialog_width">-1px</dimen>
+ <!-- Width of the zen mode interstitial dialog. -->
+ <dimen name="zen_mode_dialog_width">320dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index b5950e9..2b08141 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -26,7 +26,7 @@
public static final boolean Verbose = false;
public static class App {
- public static final boolean EnableTaskFiltering = false;
+ public static final boolean EnableTaskFiltering = true;
public static final boolean EnableTaskStackClipping = false;
public static final boolean EnableToggleNewRecentsActivity = false;
// This disables the bitmap and icon caches to
@@ -81,6 +81,10 @@
public static class Animation {
public static final int TaskRemovedReshuffleDuration = 200;
public static final int SnapScrollBackDuration = 650;
+ public static final int FilteredCurrentViewsDuration = 150;
+ public static final int FilteredNewViewsDuration = 200;
+ public static final int UnfilteredCurrentViewsDuration = 150;
+ public static final int UnfilteredNewViewsDuration = 200;
}
public static final int TaskStackOverscrollRange = 150;
@@ -107,7 +111,7 @@
public static final boolean AnimateFrontTaskIconOnEnterRecents = true;
public static final boolean AnimateFrontTaskIconOnLeavingRecents = true;
- public static final boolean UseRoundedCorners = true;
+ public static final boolean UseRoundedCorners = false;
public static final float RoundedCornerRadiusDps = 3;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b65b864..dd75921 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -54,8 +54,11 @@
finish();
}
} else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
- // Dismiss recents and launch the first task if possible
- dismissRecentsIfVisible();
+ // Try and unfilter and filtered stacks
+ if (!mRecentsView.unfilterFilteredStacks()) {
+ // If there are no filtered stacks, dismiss recents and launch the first task
+ dismissRecentsIfVisible();
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 515cec1..22363bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -66,7 +66,7 @@
// in a bottom inset
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
tsv.boundScroll();
- TaskViewTransform transform = tsv.getStackTransform(0);
+ TaskViewTransform transform = tsv.getStackTransform(0, tsv.getStackScroll());
Rect taskRect = new Rect(transform.rect);
data.putParcelable("taskRect", taskRect);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 65cbd62..928c732 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -190,7 +190,7 @@
// Load the icon
if (loadIcon == null || forceLoadTask) {
PackageManager pm = mContext.getPackageManager();
- ActivityInfo info = pm.getActivityInfo(t.key.intent.getComponent(),
+ ActivityInfo info = pm.getActivityInfo(t.key.baseIntent.getComponent(),
PackageManager.GET_META_DATA);
Drawable icon = info.loadIcon(pm);
if (!mCancelled) {
@@ -218,7 +218,7 @@
} else {
Console.logError(mContext,
"Failed to load task top thumbnail for: " +
- t.key.intent.getComponent().getPackageName());
+ t.key.baseIntent.getComponent().getPackageName());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index 33e4246..9048cba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -20,9 +20,6 @@
/* Common code */
public class Utilities {
- public static final Rect tmpRect = new Rect();
- public static final Rect tmpRect2 = new Rect();
-
/** Scales a rect about its centroid */
public static void scaleRectAboutCenter(Rect r, float scale) {
if (scale != 1.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index cda4ab2..677334d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -37,11 +37,11 @@
/* The Task Key represents the unique primary key for the task */
public static class TaskKey {
public final int id;
- public final Intent intent;
+ public final Intent baseIntent;
public TaskKey(int id, Intent intent) {
this.id = id;
- this.intent = intent;
+ this.baseIntent = intent;
}
@Override
@@ -56,7 +56,7 @@
@Override
public String toString() {
- return "Task.Key: " + id + ", " + intent.getComponent().getPackageName();
+ return "Task.Key: " + id + ", " + baseIntent.getComponent().getPackageName();
}
}
@@ -120,6 +120,6 @@
@Override
public String toString() {
- return "Task: " + key.intent.getComponent().getPackageName() + " [" + super.toString() + "]";
+ return "Task: " + key.baseIntent.getComponent().getPackageName() + " [" + super.toString() + "]";
}
}
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 f2f89ae..a0e5b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -39,9 +39,11 @@
TaskFilter mFilter;
/** Sets the task filter, saving the current touch state */
- void setFilter(TaskFilter filter) {
+ boolean setFilter(TaskFilter filter) {
+ ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
mFilter = filter;
updateFilteredTasks();
+ return !prevFilteredTasks.equals(mFilteredTasks);
}
/** Removes the task filter and returns the previous touch state */
@@ -126,9 +128,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 stack);
+ public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t);
/** Notifies when the stack was un-filtered */
- public void onStackUnfiltered(TaskStack stack);
+ public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack);
}
Context mContext;
@@ -201,29 +203,30 @@
}
/** Filters the stack into tasks similar to the one specified */
- public void filterTasks(Task t) {
+ public void filterTasks(final Task t) {
+ ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
+
// Set the task list filter
- // XXX: This is a dummy filter that currently just accepts every other task.
- mTaskList.setFilter(new TaskFilter() {
+ boolean filtered = mTaskList.setFilter(new TaskFilter() {
@Override
- public boolean acceptTask(Task t, int i) {
- if (i % 2 == 0) {
- return true;
- }
- return false;
+ public boolean acceptTask(Task at, int i) {
+ return t.key.baseIntent.getComponent().getPackageName().equals(
+ at.key.baseIntent.getComponent().getPackageName());
}
});
- if (mCb != null) {
- mCb.onStackFiltered(this);
+ if (filtered && mCb != null) {
+ mCb.onStackFiltered(this, oldStack, t);
}
}
/** Unfilters the current stack */
public void unfilterTasks() {
+ ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
+
// Unset the filter, then update the virtual scroll
mTaskList.removeFilter();
if (mCb != null) {
- mCb.onStackUnfiltered(this);
+ mCb.onStackUnfiltered(this, oldStack);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index cc85439..e89bde5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -211,17 +211,18 @@
View sourceView = tv;
int offsetX = 0;
int offsetY = 0;
+ int stackScroll = stackView.getStackScroll();
if (tv == null) {
// If there is no actual task view, then use the stack view as the source view
// and then offset to the expected transform rect, but bound this to just
// outside the display rect (to ensure we don't animate from too far away)
RecentsConfiguration config = RecentsConfiguration.getInstance();
sourceView = stackView;
- transform = stackView.getStackTransform(stack.indexOfTask(task));
+ transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
offsetX = transform.rect.left;
offsetY = Math.min(transform.rect.top, config.displayRect.height());
} else {
- transform = stackView.getStackTransform(stack.indexOfTask(task));
+ transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
}
// Compute the thumbnail to scale up from
@@ -255,7 +256,7 @@
}
} else {
// Launch the activity with the desired animation
- Intent i = new Intent(task.key.intent);
+ Intent i = new Intent(task.key.baseIntent);
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
| Intent.FLAG_ACTIVITY_NEW_TASK);
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 e7f517f..aeb571d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -34,6 +35,7 @@
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.OverScroller;
+import com.android.systemui.R;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
@@ -41,7 +43,6 @@
import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.R;
import java.util.ArrayList;
@@ -71,6 +72,7 @@
int mStackScroll;
int mMinScroll;
int mMaxScroll;
+ int mStashedScroll;
OverScroller mScroller;
ObjectAnimator mScrollAnimator;
@@ -79,6 +81,9 @@
int mStackViewsAnimationDuration;
boolean mStackViewsDirty = true;
boolean mAwaitingFirstLayout = true;
+ int[] mTmpVisibleRange = new int[2];
+ Rect mTmpRect = new Rect();
+ Rect mTmpRect2 = new Rect();
LayoutInflater mInflater;
public TaskStackView(Context context, TaskStack stack) {
@@ -102,7 +107,7 @@
}
void requestSynchronizeStackViewsWithModel(int duration) {
Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
- "[TaskStackView|requestSynchronize]", "", Console.AnsiYellow);
+ "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
if (!mStackViewsDirty) {
invalidate();
}
@@ -128,14 +133,17 @@
}
/** Update/get the transform */
- public TaskViewTransform getStackTransform(int indexInStack) {
+ public TaskViewTransform getStackTransform(int indexInStack, int stackScroll) {
TaskViewTransform transform = new TaskViewTransform();
- // Map the items to an continuous position relative to the current scroll
+ // Return early if we have an invalid index
+ if (indexInStack < 0) return transform;
+
+ // Map the items to an continuous position relative to the specified scroll
int numPeekCards = Constants.Values.TaskStackView.StackPeekNumCards;
float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
float peekHeight = Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
- float t = ((indexInStack * overlapHeight) - getStackScroll()) / overlapHeight;
+ float t = ((indexInStack * overlapHeight) - stackScroll) / overlapHeight;
float boundedT = Math.max(t, -(numPeekCards + 1));
// Set the scale relative to its position
@@ -167,25 +175,57 @@
return transform;
}
+ /**
+ * Gets the stack transforms of a list of tasks, and returns the visible range of tasks.
+ */
+ private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
+ int stackScroll,
+ int[] visibleRangeOut) {
+ // XXX: Optimization: Use binary search to find the visible range
+
+ ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
+ int taskCount = tasks.size();
+ int firstVisibleIndex = -1;
+ int lastVisibleIndex = -1;
+ for (int i = 0; i < taskCount; i++) {
+ TaskViewTransform transform = getStackTransform(i, stackScroll);
+ taskTransforms.add(transform);
+ if (transform.visible) {
+ if (firstVisibleIndex < 0) {
+ firstVisibleIndex = i;
+ }
+ lastVisibleIndex = i;
+ }
+ }
+ if (visibleRangeOut != null) {
+ visibleRangeOut[0] = firstVisibleIndex;
+ visibleRangeOut[1] = lastVisibleIndex;
+ }
+ return taskTransforms;
+ }
+
/** Synchronizes the views with the model */
void synchronizeStackViewsWithModel() {
Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|synchronizeViewsWithModel]",
"mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
if (mStackViewsDirty) {
-
- // XXX: Optimization: Use binary search to find the visible range
- // XXX: Optimize to not call getStackTransform() so many times
// XXX: Consider using TaskViewTransform pool to prevent allocations
// XXX: Iterate children views, update transforms and remove all that are not visible
// For all remaining tasks, update transforms and if visible add the view
- // Update the visible state of all the tasks
+ // Get all the task transforms
+ int[] visibleRange = mTmpVisibleRange;
+ int stackScroll = getStackScroll();
ArrayList<Task> tasks = mStack.getTasks();
+ ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll,
+ visibleRange);
+
+ // Update the visible state of all the tasks
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
- TaskViewTransform transform = getStackTransform(i);
+ TaskViewTransform transform = taskTransforms.get(i);
TaskView tv = getChildViewForTask(task);
if (transform.visible) {
@@ -194,11 +234,9 @@
// When we are picking up a new view from the view pool, prepare it for any
// following animation by putting it in a reasonable place
if (mStackViewsAnimationDuration > 0 && i != 0) {
- // XXX: We have to animate when filtering, etc. Maybe we should have a
- // runnable that ensures that tasks are animated in a special way
- // when they are entering the scene?
int fromIndex = (transform.t < 0) ? (i - 1) : (i + 1);
- tv.updateViewPropertiesFromTask(null, getStackTransform(fromIndex), 0);
+ tv.updateViewPropertiesToTaskTransform(null,
+ getStackTransform(fromIndex, stackScroll), 0);
}
}
} else {
@@ -208,17 +246,18 @@
}
}
- // Update all the current view children
+ // Update all the remaining view children
// NOTE: We have to iterate in reverse where because we are removing views directly
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
TaskView tv = (TaskView) getChildAt(i);
Task task = tv.getTask();
- TaskViewTransform transform = getStackTransform(mStack.indexOfTask(task));
- if (!transform.visible) {
+ int taskIndex = mStack.indexOfTask(task);
+ if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
mViewPool.returnViewToPool(tv);
} else {
- tv.updateViewPropertiesFromTask(null, transform, mStackViewsAnimationDuration);
+ tv.updateViewPropertiesToTaskTransform(null, taskTransforms.get(taskIndex),
+ mStackViewsAnimationDuration);
}
}
@@ -235,6 +274,10 @@
mStackScroll = value;
requestSynchronizeStackViewsWithModel();
}
+ /** Sets the current stack scroll without synchronizing the stack view with the model */
+ public void setStackScrollRaw(int value) {
+ mStackScroll = value;
+ }
/** Gets the current stack scroll */
public int getStackScroll() {
@@ -251,36 +294,39 @@
// Abort any current animations
abortScroller();
- if (mScrollAnimator != null) {
- mScrollAnimator.cancel();
- mScrollAnimator.removeAllListeners();
- }
+ abortBoundScrollAnimation();
// Start a new scroll animation
- mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
- mScrollAnimator.setDuration(duration);
- mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- setStackScroll((Integer) animation.getAnimatedValue());
- }
- });
- mScrollAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Disable hw layers on the stack
- decHwLayersRefCount("animateBoundScroll");
- }
- });
+ animateScroll(curScroll, newScroll, duration);
mScrollAnimator.start();
}
return mScrollAnimator;
}
+ /** Animates the stack scroll */
+ void animateScroll(int curScroll, int newScroll, int duration) {
+ mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
+ mScrollAnimator.setDuration(duration);
+ mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setStackScroll((Integer) animation.getAnimatedValue());
+ }
+ });
+ mScrollAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Disable hw layers on the stack
+ decHwLayersRefCount("animateBoundScroll");
+ }
+ });
+ }
+
/** Aborts any current stack scrolls */
void abortBoundScrollAnimation() {
if (mScrollAnimator != null) {
mScrollAnimator.cancel();
+ mScrollAnimator.removeAllListeners();
}
}
@@ -304,6 +350,20 @@
return false;
}
+ /**
+ * Bounds the current scroll if necessary, but does not synchronize the stack view with the
+ * model.
+ */
+ public boolean boundScrollRaw() {
+ int curScroll = getStackScroll();
+ int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll, curScroll));
+ if (newScroll != curScroll) {
+ setStackScrollRaw(newScroll);
+ return true;
+ }
+ return false;
+ }
+
/** Returns whether the current scroll is out of bounds */
boolean isScrollOutOfBounds() {
return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll);
@@ -404,12 +464,12 @@
TaskView tv = (TaskView) child;
TaskView nextTv = null;
int curIndex = indexOfChild(tv);
- if (curIndex < (getChildCount() - 1)) {
+ if ((curIndex > -1) && (curIndex < (getChildCount() - 1))) {
// Clip against the next view (if we aren't animating its alpha)
nextTv = (TaskView) getChildAt(curIndex + 1);
if (nextTv.getAlpha() == 1f) {
- Rect curRect = tv.getClippingRect(Utilities.tmpRect, false);
- Rect nextRect = nextTv.getClippingRect(Utilities.tmpRect2, true);
+ Rect curRect = tv.getClippingRect(mTmpRect, false);
+ Rect nextRect = nextTv.getClippingRect(mTmpRect2, true);
RecentsConfiguration config = RecentsConfiguration.getInstance();
// The hit rects are relative to the task view, which needs to be offset by the
// system bar height
@@ -528,9 +588,7 @@
mTaskRect.right, mStackRectSansPeek.top + mTaskRect.height());
}
- if (!mAwaitingFirstLayout) {
- requestSynchronizeStackViewsWithModel();
- } else {
+ if (mAwaitingFirstLayout) {
mAwaitingFirstLayout = false;
}
}
@@ -570,13 +628,185 @@
}
@Override
- public void onStackFiltered(TaskStack stack) {
- requestSynchronizeStackViewsWithModel();
+ 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 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);
+
+ // Bound the new stack scroll
+ updateMinMaxScroll(false);
+ boundScrollRaw();
+
+ // Compute the transforms of the items in the new stack
+ final ArrayList<TaskViewTransform> taskTransforms =
+ getStackTransforms(mStack.getTasks(), getStackScroll(), null);
+
+ // 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();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ Task task = tv.getTask();
+ TaskViewTransform toTransform;
+ int taskIndex = tasks.indexOf(task);
+ if ((taskIndex < 0) || !taskTransforms.get(taskIndex).visible) {
+ // Compose a new transform that animates the task view 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);
+ }
+ childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
+ }
+
+ AnimatorSet childViewAnimSet = new AnimatorSet();
+ childViewAnimSet.setDuration(
+ Constants.Values.TaskStackView.Animation.FilteredCurrentViewsDuration);
+ childViewAnimSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // 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
+ int taskCount = tasks.size();
+ 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);
+
+ // Animate from the current position to the new position
+ tv.prepareTaskTransformForFilterTaskVisible(fromTransform);
+ tv.updateViewPropertiesToTaskTransform(fromTransform,
+ toTransform,
+ Constants.Values.TaskStackView.Animation.FilteredNewViewsDuration);
+ }
+ }
+ }
+ invalidate();
+ }
+ });
+ childViewAnimSet.playTogether(childViewAnims);
+ childViewAnimSet.start();
}
@Override
- public void onStackUnfiltered(TaskStack stack) {
- requestSynchronizeStackViewsWithModel();
+ 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);
+
+ // Restore the stashed scroll
+ updateMinMaxScroll(false);
+ setStackScrollRaw(mStashedScroll);
+ boundScrollRaw();
+
+ // Compute the transforms of the items in the new stack
+ final ArrayList<TaskViewTransform> taskTransforms =
+ getStackTransforms(mStack.getTasks(), getStackScroll(), null);
+
+ // 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();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ Task task = tv.getTask();
+ int taskIndex = tasks.indexOf(task);
+ TaskViewTransform transform;
+
+ // If the view is no longer visible, then we should just animate it out
+ if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
+ transform = new TaskViewTransform(curTaskTransforms.get(curStack.indexOf(task)));
+ tv.prepareTaskTransformForFilterTaskVisible(transform);
+ childrenToRemove.add(tv);
+ } else {
+ transform = taskTransforms.get(taskIndex);
+ }
+ childViewAnims.add(tv.getAnimatorToTaskTransform(transform));
+ }
+
+ AnimatorSet childViewAnimSet = new AnimatorSet();
+ childViewAnimSet.setDuration(
+ Constants.Values.TaskStackView.Animation.UnfilteredCurrentViewsDuration);
+ childViewAnimSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // 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>();
+ AnimatorSet newViewAnimSet = new AnimatorSet();
+ int taskCount = tasks.size();
+ 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);
+
+ // Animate in this new view
+ TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
+ tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
+ tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+ newViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
+ offset++;
+ }
+ }
+ }
+
+ // Run the animation
+ newViewAnimSet.setDuration(
+ Constants.Values.TaskStackView.Animation.UnfilteredNewViewsDuration);
+ newViewAnimSet.playTogether(newViewAnims);
+ newViewAnimSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Decrement the hw layers ref count
+ decHwLayersRefCount("unfilteredNewViews");
+ }
+ });
+ newViewAnimSet.start();
+
+ invalidate();
+ }
+ });
+ childViewAnimSet.playTogether(childViewAnims);
+ childViewAnimSet.start();
}
/**** ViewPoolConsumer Implementation ****/
@@ -845,7 +1075,7 @@
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.DebugFlags.UI.TouchEvents,
"[TaskStackViewTouchHandler|touchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
@@ -1045,9 +1275,17 @@
ActivityManager.REMOVE_TASK_KILL_PROCESS);
}
- // If there are no remaining tasks, then just close the activity
+ // If there are no remaining tasks, then either unfilter the current stack, or just close
+ // the activity if there are no filtered stacks
if (mSv.mStack.getTaskCount() == 0) {
- activity.finish();
+ boolean shouldFinishActivity = true;
+ if (mSv.mStack.hasFilteredTasks()) {
+ mSv.mStack.unfilterTasks();
+ shouldFinishActivity = (mSv.mStack.getTaskCount() == 0);
+ }
+ if (shouldFinishActivity) {
+ activity.finish();
+ }
}
// Disable HW layers
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 c86b0e1..e04a1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,6 +16,9 @@
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.Path;
@@ -72,6 +75,7 @@
// Bind the views
mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
+ mBarView.mActivityIcon.setOnClickListener(this);
if (mTaskDataLoaded) {
onTaskDataLoaded(false);
}
@@ -90,12 +94,16 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ protected void dispatchDraw(Canvas canvas) {
+ int restoreCount = 0;
if (Constants.Values.TaskView.UseRoundedCorners) {
+ restoreCount = canvas.save();
canvas.clipPath(mRoundedRectClipPath);
}
-
- super.onDraw(canvas);
+ super.dispatchDraw(canvas);
+ if (Constants.Values.TaskView.UseRoundedCorners) {
+ canvas.restoreToCount(restoreCount);
+ }
}
/** Set callback */
@@ -109,27 +117,43 @@
}
/** Synchronizes this view's properties with the task's transform */
- void updateViewPropertiesFromTask(TaskViewTransform animateFromTransform,
- TaskViewTransform transform, int duration) {
+ void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
+ TaskViewTransform toTransform, int duration) {
if (duration > 0) {
if (animateFromTransform != null) {
setTranslationY(animateFromTransform.translationY);
setScaleX(animateFromTransform.scale);
setScaleY(animateFromTransform.scale);
+ setAlpha(animateFromTransform.alpha);
}
- animate().translationY(transform.translationY)
- .scaleX(transform.scale)
- .scaleY(transform.scale)
+ animate().translationY(toTransform.translationY)
+ .scaleX(toTransform.scale)
+ .scaleY(toTransform.scale)
+ .alpha(toTransform.alpha)
.setDuration(duration)
.setInterpolator(new AccelerateDecelerateInterpolator())
+ .withLayer()
.start();
} else {
- setTranslationY(transform.translationY);
- setScaleX(transform.scale);
- setScaleY(transform.scale);
+ setTranslationY(toTransform.translationY);
+ setScaleX(toTransform.scale);
+ setScaleY(toTransform.scale);
+ setAlpha(toTransform.alpha);
}
}
+ /** 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);
@@ -139,6 +163,17 @@
setAlpha(1f);
}
+ void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
+ // Fade the view out and slide it away
+ toTransform.alpha = 0f;
+ toTransform.translationY += 200;
+ }
+
+ void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
+ // Fade the view in
+ fromTransform.alpha = 0f;
+ }
+
/** Animates this task view as it enters recents */
public void animateOnEnterRecents() {
RecentsConfiguration config = RecentsConfiguration.getInstance();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 66c52a0..0748bbb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -23,13 +23,27 @@
public class TaskViewTransform {
public int translationY = 0;
public float scale = 1f;
- public boolean visible = true;
+ public float alpha = 1f;
+ public boolean visible = false;
public Rect rect = new Rect();
float t;
+ public TaskViewTransform() {
+ // Do nothing
+ }
+
+ public TaskViewTransform(TaskViewTransform o) {
+ translationY = o.translationY;
+ scale = o.scale;
+ alpha = o.alpha;
+ visible = o.visible;
+ rect.set(o.rect);
+ t = o.t;
+ }
+
@Override
public String toString() {
- return "TaskViewTransform y: " + translationY + " scale: " + scale +
+ return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
" visible: " + visible + " rect: " + rect;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index aed9a71..d67f7cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -911,6 +911,7 @@
d.getWindow().setAttributes(lp);
}
};
+ v.setAutoActivate(true);
v.setAdapter(new ZenModeViewAdapter(mContext) {
@Override
public void configure() {
@@ -928,7 +929,6 @@
d.create();
d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
WindowManager.LayoutParams lp = d.getWindow().getAttributes();
- lp.horizontalMargin = 0;
lp.width = mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
d.getWindow().setAttributes(lp);
d.show();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
index d1a9d57..49cf78b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -16,11 +16,8 @@
package com.android.systemui.statusbar.phone;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
@@ -39,14 +36,12 @@
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
-import com.android.systemui.R;
import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
public class ZenModeView extends RelativeLayout {
@@ -63,20 +58,21 @@
private static final long DURATION = new ValueAnimator().getDuration();
private static final long PAGER_DURATION = DURATION / 2;
- private static final float BOUNCE_SCALE = 0.8f;
private static final long CLOSE_DELAY = 600;
+ private static final long AUTO_ACTIVATE_DELAY = 100;
private final Context mContext;
- private final Paint mPathPaint;
- private final ImageView mSettingsButton;
private final TextView mModeText;
private final Switch mModeSwitch;
private final View mDivider;
private final UntilPager mUntilPager;
private final ProgressDots mProgressDots;
+ private final View mDivider2;
+ private final TextView mSettingsButton;
private Adapter mAdapter;
private boolean mInit;
+ private boolean mAutoActivate;
public ZenModeView(Context context) {
this(context, null);
@@ -90,29 +86,9 @@
final int iconSize = mContext.getResources()
.getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
final int topRowSize = iconSize * 2 / 3;
- final int p = topRowSize / 7;
+ final int p = topRowSize / 3;
- mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPathPaint.setStyle(Paint.Style.STROKE);
- mPathPaint.setColor(GRAY);
- mPathPaint.setStrokeWidth(p / 2);
-
- mSettingsButton = new ImageView(mContext);
- mSettingsButton.setPadding(p, p, p, p);
- mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal);
- LayoutParams lp = new LayoutParams(topRowSize, topRowSize);
- lp.topMargin = p;
- lp.leftMargin = p;
- addView(mSettingsButton, lp);
- mSettingsButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mAdapter != null) {
- mAdapter.configure();
- }
- bounce(mSettingsButton, null);
- }
- });
+ LayoutParams lp = null;
mModeText = new TextView(mContext);
mModeText.setText(MODE_LABEL);
@@ -120,11 +96,10 @@
mModeText.setTextColor(GRAY);
mModeText.setTypeface(CONDENSED);
mModeText.setAllCaps(true);
- mModeText.setGravity(Gravity.CENTER);
- mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.1f);
+ mModeText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
+ mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.5f);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
- lp.topMargin = p;
- lp.addRule(CENTER_HORIZONTAL);
+ lp.leftMargin = p;
addView(mModeText, lp);
mModeSwitch = new Switch(mContext);
@@ -132,6 +107,7 @@
mModeSwitch.setSwitchTypeface(CONDENSED);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
lp.topMargin = p;
+ lp.rightMargin = p;
lp.addRule(ALIGN_PARENT_RIGHT);
lp.addRule(ALIGN_BASELINE, mModeText.getId());
addView(mModeSwitch, lp);
@@ -154,11 +130,10 @@
mDivider.setBackgroundColor(GRAY);
lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
lp.addRule(BELOW, mModeText.getId());
- lp.topMargin = p;
- lp.bottomMargin = p * 2;
+ lp.bottomMargin = p;
addView(mDivider, lp);
- mUntilPager = new UntilPager(mContext, mPathPaint, iconSize * 3 / 4);
+ mUntilPager = new UntilPager(mContext, iconSize * 3 / 4);
mUntilPager.setId(android.R.id.tabhost);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.leftMargin = lp.rightMargin = iconSize / 2;
@@ -167,10 +142,41 @@
addView(mUntilPager, lp);
mProgressDots = new ProgressDots(mContext, iconSize / 5);
+ mProgressDots.setId(android.R.id.progress);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.addRule(CENTER_HORIZONTAL);
lp.addRule(BELOW, mUntilPager.getId());
addView(mProgressDots, lp);
+
+ mDivider2 = new View(mContext);
+ mDivider2.setId(android.R.id.widget_frame);
+ mDivider2.setBackgroundColor(GRAY);
+ lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
+ lp.addRule(BELOW, mProgressDots.getId());
+ addView(mDivider2, lp);
+
+ mSettingsButton = new TextView(mContext);
+ mSettingsButton.setTypeface(CONDENSED);
+ mSettingsButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSettingsButton.getTextSize() * 1.3f);
+ mSettingsButton.setPadding(p, p, p, p);
+ mSettingsButton.setText("More settings...");
+ lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ lp.addRule(BELOW, mDivider2.getId());
+ addView(mSettingsButton, lp);
+ mSettingsButton.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ mSettingsButton.setBackgroundColor(DARK_GRAY);
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ mSettingsButton.setBackground(null);
+ if (mAdapter != null) {
+ mAdapter.configure();
+ }
+ }
+ return true;
+ }
+ });
}
public void setAdapter(Adapter adapter) {
@@ -189,6 +195,27 @@
updateState(false);
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mAutoActivate) {
+ mAutoActivate = false;
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (!mModeSwitch.isChecked()) {
+ mInit = false;
+ mModeSwitch.setChecked(true);
+ }
+ }
+ }, AUTO_ACTIVATE_DELAY);
+ }
+ }
+
+ public void setAutoActivate(boolean value) {
+ mAutoActivate = value;
+ }
+
private void updateState(boolean animate) {
mUntilPager.updateState();
mModeSwitch.setChecked(mAdapter.getMode());
@@ -199,23 +226,6 @@
Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
}
- private static void bounce(final View v, final Runnable midBounce) {
- v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3)
- .setListener(new AnimatorListenerAdapter() {
- private boolean mFired;
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mFired) {
- mFired = true;
- if (midBounce != null) {
- midBounce.run();
- }
- v.animate().scaleX(1).scaleY(1).setListener(null).start();
- }
- }
- }).start();
- }
-
private final class UntilView extends FrameLayout {
private static final boolean SUPPORT_LINKS = false;
@@ -223,7 +233,7 @@
public UntilView(Context context) {
super(context);
mText = new TextView(mContext);
- mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.2f);
+ mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.3f);
mText.setTypeface(CONDENSED);
mText.setTextColor(GRAY);
mText.setGravity(Gravity.CENTER);
@@ -284,7 +294,7 @@
private int mCurrent;
private float mDownX;
- public UntilPager(Context context, Paint pathPaint, int iconSize) {
+ public UntilPager(Context context, int iconSize) {
super(context);
mViews = new UntilView[3];
for (int i = 0; i < mViews.length; i++) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a65f677..f1db904 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -145,6 +145,7 @@
TypedValue mFixedWidthMinor;
TypedValue mFixedHeightMajor;
TypedValue mFixedHeightMinor;
+ TypedValue mOutsetBottom;
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
@@ -2370,7 +2371,6 @@
} else {
h = 0;
}
-
if (h > 0) {
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -2379,6 +2379,15 @@
}
}
+ if (mOutsetBottom != null) {
+ int mode = MeasureSpec.getMode(heightMeasureSpec);
+ if (mode != MeasureSpec.UNSPECIFIED) {
+ int outset = (int) mOutsetBottom.getDimension(metrics);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
+ }
+ }
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
@@ -2993,6 +3002,10 @@
if (a.getBoolean(com.android.internal.R.styleable.Window_windowContentTransitions, false)) {
requestFeature(FEATURE_CONTENT_TRANSITIONS);
}
+ if (a.hasValue(com.android.internal.R.styleable.Window_windowOutsetBottom)) {
+ if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
+ a.getValue(com.android.internal.R.styleable.Window_windowOutsetBottom, mOutsetBottom);
+ }
final Context context = getContext();
final int targetSdk = context.getApplicationInfo().targetSdkVersion;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ededbb2..ccdacea 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3417,8 +3417,9 @@
}
final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
+ final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
if (appWindow) {
- if (showWhenLocked) {
+ if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
mAppsToBeHidden.remove(win.getAppToken());
} else {
mAppsToBeHidden.add(win.getAppToken());
@@ -3435,8 +3436,7 @@
mHideLockScreen = true;
mForceStatusBarFromKeyguard = false;
}
- if ((fl & FLAG_DISMISS_KEYGUARD) != 0
- && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
+ if (dismissKeyguard && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
if (DEBUG_LAYOUT) Slog.v(TAG,
"Setting mDismissKeyguard true by win " + win);
mDismissKeyguard = mWinDismissingKeyguard == win ?
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index 714e835..6178994 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -225,9 +225,13 @@
validate();
//android.util.Log.v("rs", "set surface " + sur + " w=" + w + ", h=" + h);
+ Surface s = null;
+ if (sur != null) {
+ s = new Surface(sur);
+ }
mWidth = w;
mHeight = h;
- nContextSetSurfaceTexture(w, h, sur);
+ nContextSetSurface(w, h, s);
}
/**
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 1a1512f..57c2f92 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2035,6 +2035,7 @@
BackupState mCurrentState;
// carried information about the current in-flight operation
+ IBackupAgent mAgentBinder;
PackageInfo mCurrentPackage;
File mSavedStateName;
File mBackupDataName;
@@ -2097,6 +2098,7 @@
addBackupTrace(b.toString());
}
+ mAgentBinder = null;
mStatus = BackupConstants.TRANSPORT_OK;
// Sanity check: if the queue is empty we have no work to do.
@@ -2228,6 +2230,7 @@
IApplicationThread.BACKUP_MODE_INCREMENTAL);
addBackupTrace("agent bound; a? = " + (agent != null));
if (agent != null) {
+ mAgentBinder = agent;
mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
// at this point we'll either get a completion callback from the
// agent, or a timeout message on the main handler. either way, we're
@@ -2253,6 +2256,7 @@
// That means we need to direct to the next state ourselves.
if (mStatus != BackupConstants.TRANSPORT_OK) {
BackupState nextState = BackupState.RUNNING_QUEUE;
+ mAgentBinder = null;
// An agent-level failure means we reenqueue this one agent for
// a later retry, but otherwise proceed normally.
@@ -2274,6 +2278,7 @@
executeNextState(nextState);
} else {
+ // success case
addBackupTrace("expecting completion/timeout callback");
}
}
@@ -2402,14 +2407,52 @@
return BackupConstants.TRANSPORT_OK;
}
+ public void failAgent(IBackupAgent agent, String message) {
+ try {
+ agent.fail(message);
+ } catch (Exception e) {
+ Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName);
+ }
+ }
+
@Override
public void operationComplete() {
- // Okay, the agent successfully reported back to us. The next thing we do is
- // push the app widget state for the app, if any.
+ // Okay, the agent successfully reported back to us!
final String pkgName = mCurrentPackage.packageName;
final long filepos = mBackupDataName.length();
FileDescriptor fd = mBackupData.getFileDescriptor();
try {
+ // If it's a 3rd party app, see whether they wrote any protected keys
+ // and complain mightily if they are attempting shenanigans.
+ if (mCurrentPackage.applicationInfo != null &&
+ (mCurrentPackage.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
+ try {
+ while (in.readNextHeader()) {
+ final String key = in.getKey();
+ if (key != null && key.charAt(0) >= 0xff00) {
+ // Not okay: crash them and bail.
+ failAgent(mAgentBinder, "Illegal backup key: " + key);
+ addBackupTrace("illegal key " + key + " from " + pkgName);
+ EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
+ "bad key");
+ mBackupHandler.removeMessages(MSG_TIMEOUT);
+ agentErrorCleanup();
+ // agentErrorCleanup() implicitly executes next state properly
+ return;
+ }
+ in.skipEntityData();
+ }
+ } finally {
+ if (readFd != null) {
+ readFd.close();
+ }
+ }
+ }
+
+ // Piggyback the widget state payload, if any
BackupDataOutput out = new BackupDataOutput(fd);
byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
UserHandle.USER_OWNER);
@@ -2434,8 +2477,7 @@
}
}
- // Spin the data off to the
- // transport and proceed with the next stage.
+ // Spin the data off to the transport and proceed with the next stage.
if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
+ pkgName);
mBackupHandler.removeMessages(MSG_TIMEOUT);
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index fe814fc..0d2cee8 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -30,7 +30,11 @@
import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
import android.os.Environment;
+import android.os.IBinder;
import android.os.RemoteException;
+import android.os.storage.IMountService;
+import android.os.ServiceManager;
+import android.os.storage.StorageManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -79,6 +83,7 @@
private final Context mContext;
private LockPatternUtils mLockPatternUtils;
+ private boolean mFirstCallToVold;
public LockSettingsService(Context context) {
mContext = context;
@@ -86,6 +91,7 @@
mOpenHelper = new DatabaseHelper(mContext);
mLockPatternUtils = new LockPatternUtils(context);
+ mFirstCallToVold = true;
}
public void systemReady() {
@@ -347,6 +353,51 @@
}
@Override
+ public boolean checkVoldPassword(int userId) throws RemoteException {
+ if (!mFirstCallToVold) {
+ return false;
+ }
+ mFirstCallToVold = false;
+
+ checkPasswordReadPermission(userId);
+
+ // There's no guarantee that this will safely connect, but if it fails
+ // we will simply show the lock screen when we shouldn't, so relatively
+ // benign. There is an outside chance something nasty would happen if
+ // this service restarted before vold stales out the password in this
+ // case. The nastiness is limited to not showing the lock screen when
+ // we should, within the first minute of decrypting the phone if this
+ // service can't connect to vold, it restarts, and then the new instance
+ // does successfully connect.
+ final IMountService service = getMountService();
+ String password = service.getPassword();
+ service.clearPassword();
+ if (password == null) {
+ return false;
+ }
+
+ try {
+ if (mLockPatternUtils.isLockPatternEnabled()) {
+ if (checkPattern(password, userId)) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ }
+
+ try {
+ if (mLockPatternUtils.isLockPasswordEnabled()) {
+ if (checkPassword(password, userId)) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ }
+
+ return false;
+ }
+
+ @Override
public void removeUser(int userId) {
checkWritePermission(userId);
@@ -524,4 +575,12 @@
Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
Secure.LOCK_SCREEN_OWNER_INFO
};
+
+ private IMountService getMountService() {
+ final IBinder service = ServiceManager.getService("mount");
+ if (service != null) {
+ return IMountService.Stub.asInterface(service);
+ }
+ return null;
+ }
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index cd74fed..c1d9fbd 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -74,6 +74,7 @@
import com.google.android.collect.Maps;
import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.DecoderException;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
@@ -573,6 +574,14 @@
}
}
+ private boolean isReady() {
+ try {
+ return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
private void handleSystemReady() {
// Snapshot current volume states since it's not safe to call into vold
// while holding locks.
@@ -2075,12 +2084,25 @@
private String toHex(String password) {
if (password == null) {
- return null;
+ return new String();
}
byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
return new String(Hex.encodeHex(bytes));
}
+ private String fromHex(String hexPassword) {
+ if (hexPassword == null) {
+ return null;
+ }
+
+ try {
+ byte[] bytes = Hex.decodeHex(hexPassword.toCharArray());
+ return new String(bytes, StandardCharsets.UTF_8);
+ } catch (DecoderException e) {
+ return null;
+ }
+ }
+
@Override
public int decryptStorage(String password) {
if (TextUtils.isEmpty(password)) {
@@ -2230,6 +2252,35 @@
}
@Override
+ public String getPassword() throws RemoteException {
+ if (!isReady()) {
+ return new String();
+ }
+
+ final NativeDaemonEvent event;
+ try {
+ event = mConnector.execute("cryptfs", "getpw");
+ return fromHex(event.getMessage());
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void clearPassword() throws RemoteException {
+ if (!isReady()) {
+ return;
+ }
+
+ final NativeDaemonEvent event;
+ try {
+ event = mConnector.execute("cryptfs", "clearpw");
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
public int mkdirs(String callingPkg, String appPath) {
final int userId = UserHandle.getUserId(Binder.getCallingUid());
final UserEnvironment userEnv = new UserEnvironment(userId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4824f30..ac6f684 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -43,6 +43,7 @@
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
+import com.android.internal.os.Zygote;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
@@ -61,8 +62,6 @@
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import dalvik.system.Zygote;
-
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 09a414e..288e8e0 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -700,7 +700,7 @@
// Just post MCS_BOUND message to trigger processing
// of next pending install.
if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Posting MCS_BOUND for next woek");
+ "Posting MCS_BOUND for next work");
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
@@ -7533,32 +7533,34 @@
mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
}
- final boolean mounted;
- if (Environment.isExternalStorageEmulated()) {
- mounted = true;
- } else {
- final String status = Environment.getExternalStorageState();
- mounted = (Environment.MEDIA_MOUNTED.equals(status)
- || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
- }
+ if (mSuccess) {
+ final boolean mounted;
+ if (Environment.isExternalStorageEmulated()) {
+ mounted = true;
+ } else {
+ final String status = Environment.getExternalStorageState();
+ mounted = (Environment.MEDIA_MOUNTED.equals(status)
+ || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
+ }
- if (mounted) {
- final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
+ if (mounted) {
+ final UserEnvironment userEnv = new UserEnvironment(mStats.userHandle);
- mStats.externalCacheSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));
+ mStats.externalCacheSize = calculateDirectorySize(mContainerService,
+ userEnv.buildExternalStorageAppCacheDirs(mStats.packageName));
- mStats.externalDataSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppDataDirs(mStats.packageName));
+ mStats.externalDataSize = calculateDirectorySize(mContainerService,
+ userEnv.buildExternalStorageAppDataDirs(mStats.packageName));
- // Always subtract cache size, since it's a subdirectory
- mStats.externalDataSize -= mStats.externalCacheSize;
+ // Always subtract cache size, since it's a subdirectory
+ mStats.externalDataSize -= mStats.externalCacheSize;
- mStats.externalMediaSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));
+ mStats.externalMediaSize = calculateDirectorySize(mContainerService,
+ userEnv.buildExternalStorageAppMediaDirs(mStats.packageName));
- mStats.externalObbSize = calculateDirectorySize(mContainerService,
- userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
+ mStats.externalObbSize = calculateDirectorySize(mContainerService,
+ userEnv.buildExternalStorageAppObbDirs(mStats.packageName));
+ }
}
}
@@ -10271,6 +10273,9 @@
final IPackageStatsObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GET_PACKAGE_SIZE, null);
+ if (packageName == null) {
+ throw new IllegalArgumentException("Attempt to get size of null packageName");
+ }
PackageStats stats = new PackageStats(packageName, userHandle);
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
new file mode 100644
index 0000000..fbfca93
--- /dev/null
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.Surface.OutOfResourcesException;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+class CircularDisplayMask {
+ private static final String TAG = "CircularDisplayMask";
+
+ private static final int STROKE_WIDTH = 2;
+
+ private final SurfaceControl mSurfaceControl;
+ private final Surface mSurface = new Surface();
+ private int mLastDW;
+ private int mLastDH;
+ private boolean mDrawNeeded;
+ private Paint mPaint;
+
+ public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) {
+ SurfaceControl ctrl = null;
+ try {
+ ctrl = new SurfaceControl(session, "CircularDisplayMask",
+ 320, 290, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+ ctrl.setLayerStack(display.getLayerStack());
+ ctrl.setLayer(zOrder);
+ ctrl.setPosition(0, 0);
+ ctrl.show();
+ mSurface.copyFrom(ctrl);
+ } catch (OutOfResourcesException e) {
+ }
+ mSurfaceControl = ctrl;
+ mDrawNeeded = true;
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setColor(Color.BLACK);
+ mPaint.setStrokeWidth(STROKE_WIDTH);
+ }
+
+ private void drawIfNeeded() {
+ if (!mDrawNeeded) {
+ return;
+ }
+ mDrawNeeded = false;
+
+ Rect dirty = new Rect(0, 0, mLastDW, mLastDH);
+ Canvas c = null;
+ try {
+ c = mSurface.lockCanvas(dirty);
+ } catch (IllegalArgumentException e) {
+ } catch (Surface.OutOfResourcesException e) {
+ }
+ if (c == null) {
+ return;
+ }
+ c.drawCircle(160, 160, 160, mPaint);
+
+ mSurface.unlockCanvasAndPost(c);
+ }
+
+ // Note: caller responsible for being inside
+ // Surface.openTransaction() / closeTransaction()
+ public void setVisibility(boolean on) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ drawIfNeeded();
+ if (on) {
+ mSurfaceControl.show();
+ } else {
+ mSurfaceControl.hide();
+ }
+ }
+
+ void positionSurface(int dw, int dh) {
+ if (mLastDW == dw && mLastDH == dh) {
+ return;
+ }
+ mLastDW = dw;
+ mLastDH = dh;
+ mSurfaceControl.setSize(dw, dh);
+ mDrawNeeded = true;
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d4670fb..2e5b8de 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -285,6 +285,8 @@
private static final String DENSITY_OVERRIDE = "ro.config.density_override";
private static final String SIZE_OVERRIDE = "ro.config.size_override";
+ private static final String SCREEN_CIRCULAR = "ro.display.circular";
+
private static final int MAX_SCREENSHOT_RETRIES = 3;
final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -422,6 +424,7 @@
final SurfaceSession mFxSession;
Watermark mWatermark;
StrictModeFlash mStrictModeFlash;
+ CircularDisplayMask mCircularDisplayMask;
FocusedStackFrame mFocusedStackFrame;
int mFocusedStackLayer;
@@ -819,6 +822,7 @@
}
LocalServices.addService(WindowManagerInternal.class, new LocalService());
+ showCircularDisplayMaskIfNeeded();
}
public InputMonitor getInputMonitor() {
@@ -5482,6 +5486,37 @@
}
}
+ public void showCircularDisplayMaskIfNeeded() {
+ if (SystemProperties.getBoolean(SCREEN_CIRCULAR, false)) {
+ mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
+ }
+ }
+
+ public void showCircularMask() {
+ synchronized(mWindowMap) {
+
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ ">>> OPEN TRANSACTION showDisplayMask");
+ SurfaceControl.openTransaction();
+ try {
+ // TODO(multi-display): support multiple displays
+ if (mCircularDisplayMask == null) {
+ mCircularDisplayMask = new CircularDisplayMask(
+ getDefaultDisplayContentLocked().getDisplay(),
+ mFxSession,
+ mPolicy.windowTypeToLayerLw(
+ WindowManager.LayoutParams.TYPE_POINTER)
+ * TYPE_LAYER_MULTIPLIER + 10);
+ }
+ mCircularDisplayMask.setVisibility(true);
+ } finally {
+ SurfaceControl.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ "<<< CLOSE TRANSACTION showDisplayMask");
+ }
+ }
+ }
+
// TODO: more accounting of which pid(s) turned it on, keep count,
// only allow disables from pids which have count on, etc.
@Override
@@ -7106,6 +7141,8 @@
public static final int REMOVE_STARTING_TIMEOUT = 33;
+ public static final int SHOW_DISPLAY_MASK = 34;
+
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -7501,6 +7538,11 @@
break;
}
+ case SHOW_DISPLAY_MASK: {
+ showCircularMask();
+ break;
+ }
+
case DO_ANIMATION_CALLBACK: {
try {
((IRemoteCallback)msg.obj).sendResult(null);
@@ -8974,6 +9016,9 @@
if (mStrictModeFlash != null) {
mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
+ if (mCircularDisplayMask != null) {
+ mCircularDisplayMask.positionSurface(defaultDw, defaultDh);
+ }
boolean focusDisplayed = false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ab4c89e..ce205c0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -50,6 +50,7 @@
import com.android.internal.R;
import com.android.internal.os.BinderInternal;
+import com.android.internal.os.Zygote;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accounts.AccountManagerService;
@@ -83,7 +84,6 @@
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
import java.io.File;
import java.util.Timer;
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 7ae5460..9ccb809 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,21 +26,25 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.util.Slog;
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;
+import java.util.Scanner;
/**
* UsbHostManager manages USB state in host mode.
*/
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>();
@@ -102,6 +107,30 @@
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);
+ }
+
+ static boolean isBuiltInUsbDevice(String deviceName) {
+ // This may be too broad an assumption
+ return deviceName.equals("/dev/bus/usb/001/001");
+ }
+
/* 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 +140,59 @@
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:UsbHostManager.usbDeviceAdded()");
+ Slog.d(TAG, "usb: nm:" + deviceName +
+ " vnd:" + vendorID +
+ " prd:" + productID +
+ " cls:" + deviceClass +
+ " sub:" + deviceSubclass +
+ " proto:" + deviceProtocol);
+ }
+
+ if (!isBuiltInUsbDevice(deviceName)) {
+ //TODO(pmclean) we will need this when we need to support USB interfaces
+ // beyond card1, device0 but turn them off for now
+ //com.android.alsascan.AlsaCardsParser cardsParser =
+ // new com.android.alsascan.AlsaCardsParser();
+ //cardsParser.scan();
+ //cardsParser.Log();
+
+ // But we need to parse the device to determine its capabilities.
+ com.android.alsascan.AlsaDevicesParser devicesParser =
+ new com.android.alsascan.AlsaDevicesParser();
+ devicesParser.scan();
+ //devicesParser.Log();
+
+ boolean hasPlaybackDevices = devicesParser.hasPlaybackDevices();
+ boolean hasCaptureDevices = devicesParser.hasCaptureDevices();
+ boolean hasMIDI = devicesParser.hasMIDIDevices();
+
+ if (DEBUG_AUDIO) {
+ Slog.d(TAG, "usb: hasPlayback:" + hasPlaybackDevices
+ + " hasCapture:" + hasCaptureDevices);
+ }
+
+ //TODO(pmclean)
+ // For now just assume that any USB device that is attached is:
+ // 1. An audio interface and
+ // 2. is card:1 device:0
+ int cardNum = 1;
+ int deviceNum = 0;
+ sendDeviceNotification(cardNum, deviceNum, true,
+ hasPlaybackDevices, hasCaptureDevices, hasMIDI);
+ }
+
if (isBlackListed(deviceName) ||
isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
return false;
@@ -176,6 +258,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()]));
@@ -204,6 +289,13 @@
/* 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);
+ }
+
+ // Same assumptions as the fake-out above
+ sendDeviceNotification(1, 0, false, /*NA*/false, /*NA*/false, /*NA*/false);
+
synchronized (mLock) {
UsbDevice device = mDevices.remove(deviceName);
if (device != null) {
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 1fa9615..cb68340 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -53,6 +53,7 @@
$(LOCAL_BUILT_MODULE): $(built_core_dep) \
$(built_framework_dep) \
$(built_ext_dep) \
+ $(built_ext_data) \
$(built_layoutlib_create_jar)
$(hide) echo "host layoutlib_create: $@"
$(hide) mkdir -p $(dir $@)
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index cfe7525..cc621c4 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -52,9 +52,9 @@
private final BridgeContext mContext;
private final boolean mPlatformFile;
- private ResourceValue[] mResourceData;
- private String[] mNames;
- private boolean[] mIsFramework;
+ private final ResourceValue[] mResourceData;
+ private final String[] mNames;
+ private final boolean[] mIsFramework;
public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
boolean platformFile) {
@@ -81,8 +81,8 @@
}
/**
- * Seals the array after all calls to {@link #bridgeSetValue(int, String, ResourceValue)} have
- * been done.
+ * Seals the array after all calls to
+ * {@link #bridgeSetValue(int, String, boolean, ResourceValue)} have been done.
* <p/>This allows to compute the list of non default values, permitting
* {@link #getIndexCount()} to return the proper value.
*/
@@ -252,7 +252,7 @@
for (String keyword : keywords) {
Integer i = map.get(keyword.trim());
if (i != null) {
- result |= i.intValue();
+ result |= i;
} else {
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
@@ -731,7 +731,7 @@
}
// not a direct id valid reference? resolve it
- Integer idValue = null;
+ Integer idValue;
if (resValue.isFramework()) {
idValue = Bridge.getResourceId(resValue.getResourceType(),
@@ -742,7 +742,7 @@
}
if (idValue != null) {
- return idValue.intValue();
+ return idValue;
}
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
@@ -753,6 +753,12 @@
return defValue;
}
+ @Override
+ public int getThemeAttributeId(int index, int defValue) {
+ // TODO: Get the right Theme Attribute ID to enable caching of the drawables.
+ return defValue;
+ }
+
/**
* Retrieve the Drawable for the attribute at <var>index</var>. This
* gets the resource ID of the selected attribute, and uses
@@ -854,6 +860,7 @@
*/
@Override
public boolean hasValue(int index) {
+ //noinspection SimplifiableIfStatement
if (index < 0 || index >= mResourceData.length) {
return false;
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 9a31705..3e75c9e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -632,8 +632,8 @@
// field instruction
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
- // name is the field's name.
- considerName(name);
+ // owner is the class that declares the field.
+ considerName(owner);
// desc is the field's descriptor (see Type).
considerDesc(desc);
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
index c988c70..2016c0e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
@@ -527,7 +527,8 @@
// field instruction
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
- // name is the field's name.
+ // owner is the class that declares the field.
+ considerName(owner);
// desc is the field's descriptor (see Type).
considerDesc(desc);
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 7ec0d38..78e2c48 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -83,6 +83,7 @@
"mock_android.dummy.InnerTest$MyStaticInnerClass",
"mock_android.dummy.InnerTest$NotStaticInner1",
"mock_android.dummy.InnerTest$NotStaticInner2",
+ "mock_android.util.EmptyArray",
"mock_android.view.View",
"mock_android.view.ViewGroup",
"mock_android.view.ViewGroup$LayoutParams",
@@ -217,15 +218,16 @@
TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>();
- ClassReader cr = mAa.findClass("mock_android.widget.TableLayout", zipClasses, keep);
+ ClassReader cr = mAa.findClass("mock_android.widget.LinearLayout", zipClasses, keep);
DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
// get first level dependencies
cr.accept(visitor, 0 /* flags */);
assertArrayEquals(new String[] {
+ "mock_android.util.EmptyArray",
"mock_android.view.ViewGroup",
- "mock_android.widget.TableLayout$LayoutParams",
+ "mock_android.widget.LinearLayout$LayoutParams",
},
out_deps.keySet().toArray());
@@ -255,7 +257,7 @@
assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
assertArrayEquals(new String[] {
- "mock_android.widget.TableLayout",
+ "mock_android.widget.LinearLayout",
}, keep.keySet().toArray());
}
}
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index 8dd0481..c6ca3c4 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java b/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java
new file mode 100644
index 0000000..aaeebf6
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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 mock_android.util;
+
+import java.lang.JavaClass;
+
+public class EmptyArray {
+
+ public static final Object[] OBJECT = new Object[0];
+}
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
index 3870a63..af56c4b 100644
--- a/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
@@ -16,11 +16,13 @@
package mock_android.widget;
+import mock_android.util.EmptyArray;
import mock_android.view.ViewGroup;
public class LinearLayout extends ViewGroup {
- public class LayoutParams extends mock_android.view.ViewGroup.LayoutParams {
+ Object[] mObjects = EmptyArray.OBJECT;
+ public class LayoutParams extends MarginLayoutParams {
}
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.java b/wifi/java/android/net/wifi/BatchedScanSettings.java
index f7ebc17..54801ad 100644
--- a/wifi/java/android/net/wifi/BatchedScanSettings.java
+++ b/wifi/java/android/net/wifi/BatchedScanSettings.java
@@ -34,17 +34,17 @@
/** Used to indicate no preference for an int value */
public final static int UNSPECIFIED = Integer.MAX_VALUE;
- // TODO - make MIN/mAX dynamic and gservices adjustable.
+ // TODO - make MIN/mAX as standard for wifi batch capability requirement.
public final static int MIN_SCANS_PER_BATCH = 2;
- public final static int MAX_SCANS_PER_BATCH = 255;
+ public final static int MAX_SCANS_PER_BATCH = 20;
public final static int DEFAULT_SCANS_PER_BATCH = MAX_SCANS_PER_BATCH;
public final static int MIN_AP_PER_SCAN = 2;
- public final static int MAX_AP_PER_SCAN = 255;
+ public final static int MAX_AP_PER_SCAN = 16;
public final static int DEFAULT_AP_PER_SCAN = 16;
- public final static int MIN_INTERVAL_SEC = 0;
- public final static int MAX_INTERVAL_SEC = 3600;
+ public final static int MIN_INTERVAL_SEC = 10;
+ public final static int MAX_INTERVAL_SEC = 500;
public final static int DEFAULT_INTERVAL_SEC = 30;
public final static int MIN_AP_FOR_DISTANCE = 0;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 12729d2..d7ecaff 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -40,8 +40,7 @@
*/
public String capabilities;
/**
- * The detected signal level in dBm. At least those are the units used by
- * the TI driver.
+ * The detected signal level in dBm.
*/
public int level;
/**
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 4a6821c..f44cb0a 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -157,9 +157,8 @@
/**
* Returns the received signal strength indicator of the current 802.11
- * network.
- * <p><strong>This is not normalized, but should be!</strong></p>
- * @return the RSSI, in the range ??? to ???
+ * network, in dBm.
+ * @return the RSSI, in the range -110 to 10
*/
public int getRssi() {
return mRssi;