summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ActivityManagerNative.java7
-rw-r--r--core/java/android/app/ActivityThread.java21
-rw-r--r--core/java/android/app/DatePickerDialog.java3
-rw-r--r--core/java/android/app/IActivityManager.java3
-rw-r--r--core/java/android/app/LoadedApk.java6
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java20
-rw-r--r--core/java/android/app/backup/BackupHelperDispatcher.java1
-rw-r--r--core/java/android/content/BroadcastReceiver.java10
-rw-r--r--core/java/android/content/Intent.java8
-rw-r--r--core/java/android/content/res/Resources.java4
-rw-r--r--core/java/android/content/res/TypedArray.java330
-rw-r--r--core/java/android/midi/IMidiDeviceServer.aidl26
-rw-r--r--core/java/android/midi/IMidiManager.aidl16
-rw-r--r--core/java/android/midi/MidiDevice.java308
-rw-r--r--core/java/android/midi/MidiDeviceInfo.java55
-rw-r--r--core/java/android/midi/MidiDeviceServer.java264
-rw-r--r--core/java/android/midi/MidiInputPort.java30
-rw-r--r--core/java/android/midi/MidiManager.java59
-rw-r--r--core/java/android/midi/MidiOutputPort.java94
-rw-r--r--core/java/android/midi/MidiPort.java86
-rw-r--r--core/java/android/os/BatteryStats.java2
-rw-r--r--core/java/android/os/Build.java43
-rw-r--r--core/java/android/os/StrictMode.java69
-rw-r--r--core/java/android/os/UserManager.java29
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/java/android/security/IKeystoreService.aidl55
-rw-r--r--core/java/android/security/IKeystoreService.java662
-rw-r--r--core/java/android/security/KeystoreArguments.aidl (renamed from core/java/android/midi/MidiDevice.aidl)9
-rw-r--r--core/java/android/security/KeystoreArguments.java76
-rw-r--r--core/java/android/view/View.java41
-rw-r--r--core/java/android/view/ViewGroup.java17
-rw-r--r--core/java/android/view/ViewParent.java20
-rw-r--r--core/java/android/view/ViewRootImpl.java39
-rw-r--r--core/java/android/view/Window.java9
-rw-r--r--core/java/android/view/WindowManagerGlobal.java1
-rw-r--r--core/java/android/widget/TextView.java11
36 files changed, 1227 insertions, 1215 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e8d08b8..0423478 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -466,8 +466,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
String resultData = data.readString();
Bundle resultExtras = data.readBundle();
boolean resultAbort = data.readInt() != 0;
+ int intentFlags = data.readInt();
if (who != null) {
- finishReceiver(who, resultCode, resultData, resultExtras, resultAbort);
+ finishReceiver(who, resultCode, resultData, resultExtras, resultAbort, intentFlags);
}
reply.writeNoException();
return true;
@@ -2848,7 +2849,8 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
- public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException
+ public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map,
+ boolean abortBroadcast, int flags) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2858,6 +2860,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeString(resultData);
data.writeBundle(map);
data.writeInt(abortBroadcast ? 1 : 0);
+ data.writeInt(flags);
mRemote.transact(FINISH_RECEIVER_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 404876f..6f0bc3a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -367,7 +367,7 @@ public final class ActivityThread {
public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, IBinder token, int sendingUser) {
super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky,
- token, sendingUser);
+ token, sendingUser, intent.getFlags());
this.intent = intent;
}
@@ -1079,8 +1079,7 @@ public final class ActivityThread {
WindowManagerGlobal.getInstance().dumpGfxInfo(fd);
}
- @Override
- public void dumpDbInfo(FileDescriptor fd, String[] args) {
+ private void dumpDatabaseInfo(FileDescriptor fd, String[] args) {
PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
PrintWriterPrinter printer = new PrintWriterPrinter(pw);
SQLiteDebug.dump(printer, args);
@@ -1088,6 +1087,22 @@ public final class ActivityThread {
}
@Override
+ public void dumpDbInfo(final FileDescriptor fd, final String[] args) {
+ if (mSystemThread) {
+ // Ensure this invocation is asynchronous to prevent
+ // writer waiting due to buffer cannot be consumed.
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+ @Override
+ public void run() {
+ dumpDatabaseInfo(fd, args);
+ }
+ });
+ } else {
+ dumpDatabaseInfo(fd, args);
+ }
+ }
+
+ @Override
public void unstableProviderDied(IBinder provider) {
sendMessage(H.UNSTABLE_PROVIDER_DIED, provider);
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index f79d32b..3fbbdff 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -131,6 +131,9 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
switch (which) {
case BUTTON_POSITIVE:
if (mDateSetListener != null) {
+ // Clearing focus forces the dialog to commit any pending
+ // changes, e.g. typed text in a NumberPicker.
+ mDatePicker.clearFocus();
mDateSetListener.onDateSet(mDatePicker, mDatePicker.getYear(),
mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index e505d69..d9fc2cf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -106,7 +106,8 @@ public interface IActivityManager extends IInterface {
String resultData, Bundle map, String requiredPermission,
int appOp, boolean serialized, boolean sticky, int userId) throws RemoteException;
public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;
- public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException;
+ public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map,
+ boolean abortBroadcast, int flags) throws RemoteException;
public void attachApplication(IApplicationThread app) throws RemoteException;
public void activityResumed(IBinder token) throws RemoteException;
public void activityIdle(IBinder token, Configuration config,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ece2a33..b01f87e 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -801,7 +801,7 @@ public final class LoadedApk {
if (extras != null) {
extras.setAllowFds(false);
}
- mgr.finishReceiver(this, resultCode, data, extras, false);
+ mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
}
@@ -826,8 +826,8 @@ public final class LoadedApk {
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
super(resultCode, resultData, resultExtras,
- mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
- ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
+ mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
+ sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c5c6d06..69872ff 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -469,20 +469,20 @@ public class DevicePolicyManager {
= "android.app.action.SET_NEW_PASSWORD";
/**
- * Flag used by {@link #addCrossProfileIntentFilter} to allow access
- * <em>from</em> a managed profile <em>to</em> its parent. That is, any
- * matching activities in the parent profile are included in the
- * disambiguation list shown when an app in the managed profile calls
- * {@link Activity#startActivity(Intent)}.
+ * Flag used by {@link #addCrossProfileIntentFilter} to allow activities in
+ * the parent profile to access intents sent from the managed profile.
+ * That is, when an app in the managed profile calls
+ * {@link Activity#startActivity(Intent)}, the intent can be resolved by a
+ * matching activity in the parent profile.
*/
public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
/**
- * Flag used by {@link #addCrossProfileIntentFilter} to allow access
- * <em>from</em> a parent <em>to</em> its managed profile. That is, any
- * matching activities in the managed profile are included in the
- * disambiguation list shown when an app in the parent profile calls
- * {@link Activity#startActivity(Intent)}.
+ * Flag used by {@link #addCrossProfileIntentFilter} to allow activities in
+ * the managed profile to access intents sent from the parent profile.
+ * That is, when an app in the parent profile calls
+ * {@link Activity#startActivity(Intent)}, the intent can be resolved by a
+ * matching activity in the managed profile.
*/
public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
diff --git a/core/java/android/app/backup/BackupHelperDispatcher.java b/core/java/android/app/backup/BackupHelperDispatcher.java
index 5466db5..6811532 100644
--- a/core/java/android/app/backup/BackupHelperDispatcher.java
+++ b/core/java/android/app/backup/BackupHelperDispatcher.java
@@ -50,7 +50,6 @@ public class BackupHelperDispatcher {
Header header = new Header();
TreeMap<String,BackupHelper> helpers = (TreeMap<String,BackupHelper>)mHelpers.clone();
FileDescriptor oldStateFD = null;
- FileDescriptor newStateFD = newState.getFileDescriptor();
if (oldState != null) {
oldStateFD = oldState.getFileDescriptor();
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 9a32fdf..af74e73 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -238,6 +238,7 @@ public abstract class BroadcastReceiver {
final boolean mInitialStickyHint;
final IBinder mToken;
final int mSendingUser;
+ final int mFlags;
int mResultCode;
String mResultData;
@@ -246,8 +247,8 @@ public abstract class BroadcastReceiver {
boolean mFinished;
/** @hide */
- public PendingResult(int resultCode, String resultData, Bundle resultExtras,
- int type, boolean ordered, boolean sticky, IBinder token, int userId) {
+ public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
+ boolean ordered, boolean sticky, IBinder token, int userId, int flags) {
mResultCode = resultCode;
mResultData = resultData;
mResultExtras = resultExtras;
@@ -256,6 +257,7 @@ public abstract class BroadcastReceiver {
mInitialStickyHint = sticky;
mToken = token;
mSendingUser = userId;
+ mFlags = flags;
}
/**
@@ -417,11 +419,11 @@ public abstract class BroadcastReceiver {
}
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
- mAbortBroadcast);
+ mAbortBroadcast, mFlags);
} else {
// This broadcast was sent to a component; it is not ordered,
// but we still need to tell the activity manager we are done.
- am.finishReceiver(mToken, 0, null, null, false);
+ am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
} catch (RemoteException ex) {
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 5ebbf16..af7ec5e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3949,10 +3949,12 @@ public class Intent implements Parcelable, Cloneable {
* is:
*
* <pre class="prettyprint">
- * android-app://{package_id}/{scheme}/{host}/{path}{#Intent;...}</pre>
+ * android-app://{package_id}[/{scheme}[/{host}[/{path}]]][#Intent;{...}]</pre>
*
- * <p>In this scheme, only the <code>pacakge_id</code> is required, and all
- * other components can be included as desired. Note that this can not be
+ * <p>In this scheme, only the <code>package_id</code> is required. If you include a host,
+ * you must also include a scheme; including a path also requires both a host and a scheme.
+ * The final #Intent; fragment can be used without a scheme, host, or path.
+ * Note that this can not be
* used with intents that have a {@link #setSelector}, since the base intent
* will always have an explicit package name.</p>
*
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c5c8d75..c931c01 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2696,8 +2696,8 @@ public class Resources {
private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
if (value.string == null) {
- throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
- + Integer.toHexString(id) + ") is not a ColorStateList: " + value);
+ throw new UnsupportedOperationException(
+ "Can't convert to color state list: type=0x" + value.type);
}
final String file = value.string.toString();
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 06c701a..f15b6b9 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -18,6 +18,7 @@ package android.content.res;
import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
+import android.os.StrictMode;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -73,7 +74,9 @@ public class TypedArray {
/*package*/ TypedValue mValue = new TypedValue();
/**
- * Return the number of values in this array.
+ * Returns the number of values in this array.
+ *
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public int length() {
if (mRecycled) {
@@ -85,6 +88,8 @@ public class TypedArray {
/**
* Return the number of indices in the array that actually have data.
+ *
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public int getIndexCount() {
if (mRecycled) {
@@ -95,13 +100,14 @@ public class TypedArray {
}
/**
- * Return an index in the array that has data.
+ * Returns an index in the array that has data.
*
* @param at The index you would like to returned, ranging from 0 to
- * {@link #getIndexCount()}.
+ * {@link #getIndexCount()}.
*
* @return The index at the given offset, which can be used with
- * {@link #getValue} and related APIs.
+ * {@link #getValue} and related APIs.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public int getIndex(int at) {
if (mRecycled) {
@@ -112,7 +118,9 @@ public class TypedArray {
}
/**
- * Return the Resources object this array was loaded from.
+ * Returns the Resources object this array was loaded from.
+ *
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public Resources getResources() {
if (mRecycled) {
@@ -123,12 +131,17 @@ public class TypedArray {
}
/**
- * Retrieve the styled string value for the attribute at <var>index</var>.
+ * Retrieves the styled string value for the attribute at <var>index</var>.
+ * <p>
+ * If the attribute is not a string, this method will attempt to coerce
+ * it to a string.
*
* @param index Index of attribute to retrieve.
*
- * @return CharSequence holding string data. May be styled. Returns
- * null if the attribute is not defined.
+ * @return CharSequence holding string data. May be styled. Returns
+ * {@code null} if the attribute is not defined or could not be
+ * coerced to a string.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public CharSequence getText(int index) {
if (mRecycled) {
@@ -144,23 +157,28 @@ public class TypedArray {
return loadStringValueAt(index);
}
- TypedValue v = mValue;
+ final TypedValue v = mValue;
if (getValueAt(index, v)) {
- Log.w(Resources.TAG, "Converting to string: " + v);
+ StrictMode.noteResourceMismatch(v);
return v.coerceToString();
}
- Log.w(Resources.TAG, "getString of bad type: 0x"
- + Integer.toHexString(type));
- return null;
+
+ // We already checked for TYPE_NULL. This should never happen.
+ throw new RuntimeException("getText of bad type: 0x" + Integer.toHexString(type));
}
/**
- * Retrieve the string value for the attribute at <var>index</var>.
+ * Retrieves the string value for the attribute at <var>index</var>.
+ * <p>
+ * If the attribute is not a string, this method will attempt to coerce
+ * it to a string.
*
* @param index Index of attribute to retrieve.
*
- * @return String holding string data. Any styling information is
- * removed. Returns null if the attribute is not defined.
+ * @return String holding string data. Any styling information is removed.
+ * Returns {@code null} if the attribute is not defined or could
+ * not be coerced to a string.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public String getString(int index) {
if (mRecycled) {
@@ -176,19 +194,19 @@ public class TypedArray {
return loadStringValueAt(index).toString();
}
- TypedValue v = mValue;
+ final TypedValue v = mValue;
if (getValueAt(index, v)) {
- Log.w(Resources.TAG, "Converting to string: " + v);
- CharSequence cs = v.coerceToString();
+ StrictMode.noteResourceMismatch(v);
+ final CharSequence cs = v.coerceToString();
return cs != null ? cs.toString() : null;
}
- Log.w(Resources.TAG, "getString of bad type: 0x"
- + Integer.toHexString(type));
- return null;
+
+ // We already checked for TYPE_NULL. This should never happen.
+ throw new RuntimeException("getString of bad type: 0x" + Integer.toHexString(type));
}
/**
- * Retrieve the string value for the attribute at <var>index</var>, but
+ * Retrieves the string value for the attribute at <var>index</var>, but
* only if that string comes from an immediate value in an XML file. That
* is, this does not allow references to string resources, string
* attributes, or conversions from other types. As such, this method
@@ -197,9 +215,10 @@ public class TypedArray {
*
* @param index Index of attribute to retrieve.
*
- * @return String holding string data. Any styling information is
- * removed. Returns null if the attribute is not defined or is not
- * an immediate string value.
+ * @return String holding string data. Any styling information is removed.
+ * Returns {@code null} if the attribute is not defined or is not
+ * an immediate string value.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public String getNonResourceString(int index) {
if (mRecycled) {
@@ -220,16 +239,17 @@ public class TypedArray {
}
/**
- * @hide
- * Retrieve the string value for the attribute at <var>index</var> that is
+ * Retrieves the string value for the attribute at <var>index</var> that is
* not allowed to change with the given configurations.
*
* @param index Index of attribute to retrieve.
* @param allowedChangingConfigs Bit mask of configurations from
- * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
+ * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
*
- * @return String holding string data. Any styling information is
- * removed. Returns null if the attribute is not defined.
+ * @return String holding string data. Any styling information is removed.
+ * Returns {@code null} if the attribute is not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @hide
*/
public String getNonConfigurationString(int index, int allowedChangingConfigs) {
if (mRecycled) {
@@ -248,24 +268,33 @@ public class TypedArray {
return loadStringValueAt(index).toString();
}
- TypedValue v = mValue;
+ final TypedValue v = mValue;
if (getValueAt(index, v)) {
- Log.w(Resources.TAG, "Converting to string: " + v);
- CharSequence cs = v.coerceToString();
+ StrictMode.noteResourceMismatch(v);
+ final CharSequence cs = v.coerceToString();
return cs != null ? cs.toString() : null;
}
- Log.w(Resources.TAG, "getString of bad type: 0x"
- + Integer.toHexString(type));
- return null;
+
+ // We already checked for TYPE_NULL. This should never happen.
+ throw new RuntimeException("getNonConfigurationString of bad type: 0x"
+ + Integer.toHexString(type));
}
/**
* Retrieve the boolean value for the attribute at <var>index</var>.
+ * <p>
+ * If the attribute is an integer value, this method will return whether
+ * it is equal to zero. If the attribute is not a boolean or integer value,
+ * this method will attempt to coerce it to an integer using
+ * {@link Integer#decode(String)} and return whether it is equal to zero.
*
* @param index Index of attribute to retrieve.
- * @param defValue Value to return if the attribute is not defined.
+ * @param defValue Value to return if the attribute is not defined or
+ * cannot be coerced to an integer.
*
- * @return Attribute boolean value, or defValue if not defined.
+ * @return Boolean value of the attribute, or defValue if the attribute was
+ * not defined or could not be coerced to an integer.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean getBoolean(int index, boolean defValue) {
if (mRecycled) {
@@ -278,28 +307,33 @@ public class TypedArray {
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
- && type <= TypedValue.TYPE_LAST_INT) {
+ && type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA] != 0;
}
- TypedValue v = mValue;
+ final TypedValue v = mValue;
if (getValueAt(index, v)) {
- Log.w(Resources.TAG, "Converting to boolean: " + v);
- return XmlUtils.convertValueToBoolean(
- v.coerceToString(), defValue);
+ StrictMode.noteResourceMismatch(v);
+ return XmlUtils.convertValueToBoolean(v.coerceToString(), defValue);
}
- Log.w(Resources.TAG, "getBoolean of bad type: 0x"
- + Integer.toHexString(type));
- return defValue;
+
+ // We already checked for TYPE_NULL. This should never happen.
+ throw new RuntimeException("getBoolean of bad type: 0x" + Integer.toHexString(type));
}
/**
* Retrieve the integer value for the attribute at <var>index</var>.
+ * <p>
+ * If the attribute is not an integer, this method will attempt to coerce
+ * it to an integer using {@link Integer#decode(String)}.
*
* @param index Index of attribute to retrieve.
- * @param defValue Value to return if the attribute is not defined.
+ * @param defValue Value to return if the attribute is not defined or
+ * cannot be coerced to an integer.
*
- * @return Attribute int value, or defValue if not defined.
+ * @return Integer value of the attribute, or defValue if the attribute was
+ * not defined or could not be coerced to an integer.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public int getInt(int index, int defValue) {
if (mRecycled) {
@@ -312,27 +346,31 @@ public class TypedArray {
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
- && type <= TypedValue.TYPE_LAST_INT) {
+ && type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
}
- TypedValue v = mValue;
+ final TypedValue v = mValue;
if (getValueAt(index, v)) {
- Log.w(Resources.TAG, "Converting to int: " + v);
- return XmlUtils.convertValueToInt(
- v.coerceToString(), defValue);
+ StrictMode.noteResourceMismatch(v);
+ return XmlUtils.convertValueToInt(v.coerceToString(), defValue);
}
- Log.w(Resources.TAG, "getInt of bad type: 0x"
- + Integer.toHexString(type));
- return defValue;
+
+ // We already checked for TYPE_NULL. This should never happen.
+ throw new RuntimeException("getInt of bad type: 0x" + Integer.toHexString(type));
}
/**
* Retrieve the float value for the attribute at <var>index</var>.
+ * <p>
+ * If the attribute is not a float or an integer, this method will attempt
+ * to coerce it to a float using {@link Float#parseFloat(String)}.
*
* @param index Index of attribute to retrieve.
*
- * @return Attribute float value, or defValue if not defined..
+ * @return Attribute float value, or defValue if the attribute was
+ * not defined or could not be coerced to a float.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public float getFloat(int index, float defValue) {
if (mRecycled) {
@@ -347,21 +385,21 @@ public class TypedArray {
} else if (type == TypedValue.TYPE_FLOAT) {
return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
} else if (type >= TypedValue.TYPE_FIRST_INT
- && type <= TypedValue.TYPE_LAST_INT) {
+ && type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
}
- TypedValue v = mValue;
+ final TypedValue v = mValue;
if (getValueAt(index, v)) {
- Log.w(Resources.TAG, "Converting to float: " + v);
- CharSequence str = v.coerceToString();
+ final CharSequence str = v.coerceToString();
if (str != null) {
+ StrictMode.noteResourceMismatch(v);
return Float.parseFloat(str.toString());
}
}
- Log.w(Resources.TAG, "getFloat of bad type: 0x"
- + Integer.toHexString(type));
- return defValue;
+
+ // We already checked for TYPE_NULL. This should never happen.
+ throw new RuntimeException("getFloat of bad type: 0x" + Integer.toHexString(type));
}
/**
@@ -369,12 +407,18 @@ public class TypedArray {
* the attribute references a color resource holding a complex
* {@link android.content.res.ColorStateList}, then the default color from
* the set is returned.
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not an integer color or color state list.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute color value, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not an integer color or color state list.
*/
public int getColor(int index, int defValue) {
if (mRecycled) {
@@ -387,7 +431,7 @@ public class TypedArray {
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
- && type <= TypedValue.TYPE_LAST_INT) {
+ && type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_STRING) {
final TypedValue value = mValue;
@@ -398,7 +442,8 @@ public class TypedArray {
}
return defValue;
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to color: type=0x"
@@ -408,12 +453,22 @@ public class TypedArray {
/**
* Retrieve the ColorStateList for the attribute at <var>index</var>.
* The value may be either a single solid color or a reference to
- * a color or complex {@link android.content.res.ColorStateList} description.
+ * a color or complex {@link android.content.res.ColorStateList}
+ * description.
+ * <p>
+ * This method will return {@code null} if the attribute is not defined or
+ * is not an integer color or color state list.
*
* @param index Index of attribute to retrieve.
*
- * @return ColorStateList for the attribute, or null if not defined.
+ * @return ColorStateList for the attribute, or {@code null} if not
+ * defined.
+ * @throws RuntimeException if the attribute if the TypedArray has already
+ * been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not an integer color or color state list.
*/
+ @Nullable
public ColorStateList getColorStateList(int index) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
@@ -422,7 +477,8 @@ public class TypedArray {
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
return mResources.loadColorStateList(value, value.resourceId, mTheme);
}
@@ -431,12 +487,18 @@ public class TypedArray {
/**
* Retrieve the integer value for the attribute at <var>index</var>.
+ * <p>
+ * Unlike {@link #getInt(int, int)}, this method will throw an exception if
+ * the attribute is defined but is not an integer.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute integer value, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not an integer.
*/
public int getInteger(int index, int defValue) {
if (mRecycled) {
@@ -449,10 +511,11 @@ public class TypedArray {
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
- && type <= TypedValue.TYPE_LAST_INT) {
+ && type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to integer: type=0x"
@@ -460,17 +523,23 @@ public class TypedArray {
}
/**
- * Retrieve a dimensional unit attribute at <var>index</var>. Unit
+ * Retrieve a dimensional unit attribute at <var>index</var>. Unit
* conversions are based on the current {@link DisplayMetrics}
* associated with the resources this {@link TypedArray} object
* came from.
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not a dimension.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute dimension value multiplied by the appropriate
- * metric, or defValue if not defined.
+ * metric, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not an integer.
*
* @see #getDimensionPixelOffset
* @see #getDimensionPixelSize
@@ -487,9 +556,10 @@ public class TypedArray {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimension(
- data[index+AssetManager.STYLE_DATA], mMetrics);
+ data[index + AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -502,13 +572,19 @@ public class TypedArray {
* {@link #getDimension}, except the returned value is converted to
* integer pixels for you. An offset conversion involves simply
* truncating the base value to an integer.
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not a dimension.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute dimension value multiplied by the appropriate
- * metric and truncated to integer pixels, or defValue if not defined.
+ * metric and truncated to integer pixels, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not an integer.
*
* @see #getDimension
* @see #getDimensionPixelSize
@@ -525,9 +601,10 @@ public class TypedArray {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelOffset(
- data[index+AssetManager.STYLE_DATA], mMetrics);
+ data[index + AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -541,13 +618,19 @@ public class TypedArray {
* integer pixels for use as a size. A size conversion involves
* rounding the base value, and ensuring that a non-zero base value
* is at least one pixel in size.
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not a dimension.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute dimension value multiplied by the appropriate
- * metric and truncated to integer pixels, or defValue if not defined.
+ * metric and truncated to integer pixels, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not a dimension.
*
* @see #getDimension
* @see #getDimensionPixelOffset
@@ -566,7 +649,8 @@ public class TypedArray {
return TypedValue.complexToDimensionPixelSize(
data[index+AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -578,12 +662,18 @@ public class TypedArray {
* {@link android.view.ViewGroup}'s layout_width and layout_height
* attributes. This is only here for performance reasons; applications
* should use {@link #getDimensionPixelSize}.
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not a dimension or integer (enum).
*
* @param index Index of the attribute to retrieve.
* @param name Textual name of attribute for error reporting.
*
* @return Attribute dimension value multiplied by the appropriate
- * metric and truncated to integer pixels.
+ * metric and truncated to integer pixels.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not a dimension or integer (enum).
*/
public int getLayoutDimension(int index, String name) {
if (mRecycled) {
@@ -600,10 +690,11 @@ public class TypedArray {
return TypedValue.complexToDimensionPixelSize(
data[index+AssetManager.STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
- throw new RuntimeException(getPositionDescription()
+ throw new UnsupportedOperationException(getPositionDescription()
+ ": You must supply a " + name + " attribute.");
}
@@ -615,10 +706,11 @@ public class TypedArray {
*
* @param index Index of the attribute to retrieve.
* @param defValue The default value to return if this attribute is not
- * default or contains the wrong type of data.
+ * default or contains the wrong type of data.
*
* @return Attribute dimension value multiplied by the appropriate
- * metric and truncated to integer pixels.
+ * metric and truncated to integer pixels.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public int getLayoutDimension(int index, int defValue) {
if (mRecycled) {
@@ -633,14 +725,14 @@ public class TypedArray {
return data[index+AssetManager.STYLE_DATA];
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelSize(
- data[index+AssetManager.STYLE_DATA], mMetrics);
+ data[index + AssetManager.STYLE_DATA], mMetrics);
}
return defValue;
}
/**
- * Retrieve a fractional unit attribute at <var>index</var>.
+ * Retrieves a fractional unit attribute at <var>index</var>.
*
* @param index Index of attribute to retrieve.
* @param base The base value of this fraction. In other words, a
@@ -652,7 +744,10 @@ public class TypedArray {
* not a resource.
*
* @return Attribute fractional value multiplied by the appropriate
- * base value, or defValue if not defined.
+ * base value, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not a fraction.
*/
public float getFraction(int index, int base, int pbase, float defValue) {
if (mRecycled) {
@@ -668,7 +763,8 @@ public class TypedArray {
return TypedValue.complexToFraction(
data[index+AssetManager.STYLE_DATA], base, pbase);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
@@ -676,7 +772,7 @@ public class TypedArray {
}
/**
- * Retrieve the resource identifier for the attribute at
+ * Retrieves the resource identifier for the attribute at
* <var>index</var>. Note that attribute resource as resolved when
* the overall {@link TypedArray} object is retrieved. As a
* result, this function will return the resource identifier of the
@@ -688,6 +784,7 @@ public class TypedArray {
* not a resource.
*
* @return Attribute resource identifier, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public int getResourceId(int index, int defValue) {
if (mRecycled) {
@@ -706,13 +803,15 @@ public class TypedArray {
}
/**
- * Retrieve the theme attribute resource identifier for the attribute at
+ * Retrieves the theme attribute resource identifier for the attribute at
* <var>index</var>.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or not a
- * resource.
+ * resource.
+ *
* @return Theme attribute resource identifier, or defValue if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
* @hide
*/
public int getThemeAttributeId(int index, int defValue) {
@@ -730,10 +829,16 @@ public class TypedArray {
/**
* Retrieve the Drawable for the attribute at <var>index</var>.
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not a color or drawable resource.
*
* @param index Index of attribute to retrieve.
*
- * @return Drawable for the attribute, or null if not defined.
+ * @return Drawable for the attribute, or {@code null} if not defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not a color or drawable resource.
*/
@Nullable
public Drawable getDrawable(int index) {
@@ -744,7 +849,8 @@ public class TypedArray {
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
- throw new RuntimeException("Failed to resolve attribute at index " + index);
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index);
}
return mResources.loadDrawable(value, value.resourceId, mTheme);
}
@@ -756,10 +862,15 @@ public class TypedArray {
* This gets the resource ID of the selected attribute, and uses
* {@link Resources#getTextArray Resources.getTextArray} of the owning
* Resources object to retrieve its String[].
+ * <p>
+ * This method will throw an exception if the attribute is defined but is
+ * not a text array resource.
*
* @param index Index of attribute to retrieve.
*
- * @return CharSequence[] for the attribute, or null if not defined.
+ * @return CharSequence[] for the attribute, or {@code null} if not
+ * defined.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public CharSequence[] getTextArray(int index) {
if (mRecycled) {
@@ -780,7 +891,8 @@ public class TypedArray {
* @param outValue TypedValue object in which to place the attribute's
* data.
*
- * @return Returns true if the value was retrieved, else false.
+ * @return {@code true} if the value was retrieved, false otherwise.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean getValue(int index, TypedValue outValue) {
if (mRecycled) {
@@ -794,7 +906,9 @@ public class TypedArray {
* Returns the type of attribute at the specified index.
*
* @param index Index of attribute whose type to retrieve.
+ *
* @return Attribute type.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public int getType(int index) {
if (mRecycled) {
@@ -814,6 +928,7 @@ public class TypedArray {
* @param index Index of attribute to retrieve.
*
* @return True if the attribute has a value, false otherwise.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean hasValue(int index) {
if (mRecycled) {
@@ -834,6 +949,7 @@ public class TypedArray {
* @param index Index of attribute to retrieve.
*
* @return True if the attribute has a value or is empty, false otherwise.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean hasValueOrEmpty(int index) {
if (mRecycled) {
@@ -857,6 +973,7 @@ public class TypedArray {
* @return Returns a TypedValue object if the attribute is defined,
* containing its data; otherwise returns null. (You will not
* receive a TypedValue whose type is TYPE_NULL.)
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public TypedValue peekValue(int index) {
if (mRecycled) {
@@ -872,6 +989,9 @@ public class TypedArray {
/**
* Returns a message about the parser state suitable for printing error messages.
+ *
+ * @return Human-readable description of current parser state.
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public String getPositionDescription() {
if (mRecycled) {
@@ -882,8 +1002,10 @@ public class TypedArray {
}
/**
- * Recycle the TypedArray, to be re-used by a later caller. After calling
+ * Recycles the TypedArray, to be re-used by a later caller. After calling
* this function you must not ever touch the typed array again.
+ *
+ * @throws RuntimeException if the TypedArray has already been recycled.
*/
public void recycle() {
if (mRecycled) {
@@ -905,9 +1027,10 @@ public class TypedArray {
* Removes the entries from the typed array so that subsequent calls to typed
* getters will return the default value without crashing.
*
- * @return An array of length {@link #getIndexCount()} populated with theme
- * attributes, or {@code null} if there are no theme attributes in
- * the typed array.
+ * @return an array of length {@link #getIndexCount()} populated with theme
+ * attributes, or null if there are no theme attributes in the typed
+ * array
+ * @throws RuntimeException if the TypedArray has already been recycled.
* @hide
*/
@Nullable
@@ -966,9 +1089,14 @@ public class TypedArray {
*
* @return Returns a mask of the changing configuration parameters, as
* defined by {@link android.content.pm.ActivityInfo}.
+ * @throws RuntimeException if the TypedArray has already been recycled.
* @see android.content.pm.ActivityInfo
*/
public int getChangingConfigurations() {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
int changingConfig = 0;
final int[] data = mData;
diff --git a/core/java/android/midi/IMidiDeviceServer.aidl b/core/java/android/midi/IMidiDeviceServer.aidl
new file mode 100644
index 0000000..31fdbbb
--- /dev/null
+++ b/core/java/android/midi/IMidiDeviceServer.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.midi;
+
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface IMidiDeviceServer
+{
+ ParcelFileDescriptor openInputPort(int portNumber);
+ ParcelFileDescriptor openOutputPort(int portNumber);
+}
diff --git a/core/java/android/midi/IMidiManager.aidl b/core/java/android/midi/IMidiManager.aidl
index 7a9f887..575b525 100644
--- a/core/java/android/midi/IMidiManager.aidl
+++ b/core/java/android/midi/IMidiManager.aidl
@@ -16,13 +16,11 @@
package android.midi;
-import android.hardware.usb.UsbDevice;
+import android.midi.IMidiDeviceServer;
import android.midi.IMidiListener;
-import android.midi.MidiDevice;
import android.midi.MidiDeviceInfo;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
/** @hide */
interface IMidiManager
@@ -34,14 +32,10 @@ interface IMidiManager
void unregisterListener(IBinder token, in IMidiListener listener);
// for communicating with MIDI devices
- ParcelFileDescriptor openDevice(IBinder token, in MidiDeviceInfo device);
+ IMidiDeviceServer openDevice(IBinder token, in MidiDeviceInfo device);
// for implementing virtual MIDI devices
- MidiDevice registerVirtualDevice(IBinder token, int numInputPorts, int numOutputPorts,
- in Bundle properties);
- void unregisterVirtualDevice(IBinder token, in MidiDeviceInfo device);
-
- // for use by UsbAudioManager
- void alsaDeviceAdded(int card, int device, in UsbDevice usbDevice);
- void alsaDeviceRemoved(in UsbDevice usbDevice);
+ MidiDeviceInfo registerDeviceServer(in IMidiDeviceServer server, int numInputPorts,
+ int numOutputPorts, in Bundle properties, boolean isPrivate, int type);
+ void unregisterDeviceServer(in IMidiDeviceServer server);
}
diff --git a/core/java/android/midi/MidiDevice.java b/core/java/android/midi/MidiDevice.java
index 7f83896..8aaa86d 100644
--- a/core/java/android/midi/MidiDevice.java
+++ b/core/java/android/midi/MidiDevice.java
@@ -16,9 +16,8 @@
package android.midi;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.util.Log;
import java.io.FileDescriptor;
@@ -30,114 +29,31 @@ import java.util.ArrayList;
/**
* This class is used for sending and receiving data to and from an MIDI device
* Instances of this class are created by {@link MidiManager#openDevice}.
- * This class can also be used to provide the implementation for a virtual device.
- *
- * This class implements Parcelable so it can be returned from MidiService when creating
- * virtual MIDI devices.
*
* @hide
*/
-public final class MidiDevice implements Parcelable {
+public final class MidiDevice {
private static final String TAG = "MidiDevice";
private final MidiDeviceInfo mDeviceInfo;
- private ParcelFileDescriptor mParcelFileDescriptor;
- private FileInputStream mInputStream;
- private FileOutputStream mOutputStream;
-
- // lazily populated lists of ports
- private final MidiInputPort[] mInputPorts;
- private final MidiOutputPort[] mOutputPorts;
-
- // array of receiver lists, indexed by port number
- private final ArrayList<MidiReceiver>[] mReceivers;
-
- private int mReceiverCount; // total number of receivers for all ports
+ private final IMidiDeviceServer mServer;
- /**
- * Minimum size of packed message as sent through our ParcelFileDescriptor
- * 8 bytes for timestamp, 1 byte for port number and 1 to 3 bytes for message
+ /**
+ * MidiDevice should only be instantiated by MidiManager
* @hide
*/
- public static final int MIN_PACKED_MESSAGE_SIZE = 10;
+ public MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
+ mDeviceInfo = deviceInfo;
+ mServer = server;
+ }
/**
- * Maximum size of packed message as sent through our ParcelFileDescriptor
- * 8 bytes for timestamp, 1 byte for port number and 1 to 3 bytes for message
- * @hide
- */
- public static final int MAX_PACKED_MESSAGE_SIZE = 12;
-
- // This thread reads MIDI events from a socket and distributes them to the list of
- // MidiReceivers attached to this device.
- private final Thread mThread = new Thread() {
- @Override
- public void run() {
- byte[] buffer = new byte[MAX_PACKED_MESSAGE_SIZE];
- ArrayList<MidiReceiver> deadReceivers = new ArrayList<MidiReceiver>();
-
- try {
- while (true) {
- // read next event
- int count = mInputStream.read(buffer);
- if (count < MIN_PACKED_MESSAGE_SIZE || count > MAX_PACKED_MESSAGE_SIZE) {
- Log.e(TAG, "Number of bytes read out of range: " + count);
- break;
- }
-
- int offset = getMessageOffset(buffer, count);
- int size = getMessageSize(buffer, count);
- long timestamp = getMessageTimeStamp(buffer, count);
- int port = getMessagePortNumber(buffer, count);
-
- synchronized (mReceivers) {
- ArrayList<MidiReceiver> receivers = mReceivers[port];
- if (receivers != null) {
- for (int i = 0; i < receivers.size(); i++) {
- MidiReceiver receiver = receivers.get(i);
- try {
- receivers.get(i).onPost(buffer, offset, size, timestamp);
- } catch (IOException e) {
- Log.e(TAG, "post failed");
- deadReceivers.add(receiver);
- }
- }
- // remove any receivers that failed
- if (deadReceivers.size() > 0) {
- for (MidiReceiver receiver: deadReceivers) {
- receivers.remove(receiver);
- mReceiverCount--;
- }
- deadReceivers.clear();
- }
- if (receivers.size() == 0) {
- mReceivers[port] = null;
- }
- // exit if we have no receivers left
- if (mReceiverCount == 0) {
- break;
- }
- }
- }
- }
- } catch (IOException e) {
- Log.e(TAG, "read failed");
- }
- }
- };
-
- /**
- * MidiDevice should only be instantiated by MidiManager or MidiService
- * @hide
+ * Returns a {@link MidiDeviceInfo} object, which describes this device.
+ *
+ * @return the {@link MidiDeviceInfo} object
*/
- public MidiDevice(MidiDeviceInfo deviceInfo, ParcelFileDescriptor pfd) {
- mDeviceInfo = deviceInfo;
- mParcelFileDescriptor = pfd;
- int inputPorts = deviceInfo.getInputPortCount();
- int outputPorts = deviceInfo.getOutputPortCount();
- mInputPorts = new MidiInputPort[inputPorts];
- mOutputPorts = new MidiOutputPort[outputPorts];
- mReceivers = new ArrayList[outputPorts];
+ public MidiDeviceInfo getInfo() {
+ return mDeviceInfo;
}
/**
@@ -147,14 +63,15 @@ public final class MidiDevice implements Parcelable {
* @return the {@link MidiInputPort}
*/
public MidiInputPort openInputPort(int portNumber) {
- if (portNumber < 0 || portNumber >= mDeviceInfo.getInputPortCount()) {
- throw new IllegalArgumentException("input port number out of range");
- }
- synchronized (mInputPorts) {
- if (mInputPorts[portNumber] == null) {
- mInputPorts[portNumber] = new MidiInputPort(mOutputStream, portNumber);
+ try {
+ ParcelFileDescriptor pfd = mServer.openInputPort(portNumber);
+ if (pfd == null) {
+ return null;
}
- return mInputPorts[portNumber];
+ return new MidiInputPort(pfd, portNumber);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openInputPort");
+ return null;
}
}
@@ -165,185 +82,20 @@ public final class MidiDevice implements Parcelable {
* @return the {@link MidiOutputPort}
*/
public MidiOutputPort openOutputPort(int portNumber) {
- if (portNumber < 0 || portNumber >= mDeviceInfo.getOutputPortCount()) {
- throw new IllegalArgumentException("output port number out of range");
- }
- synchronized (mOutputPorts) {
- if (mOutputPorts[portNumber] == null) {
- mOutputPorts[portNumber] = new MidiOutputPort(this, portNumber);
- }
- return mOutputPorts[portNumber];
- }
- }
-
- /* package */ void connect(MidiReceiver receiver, int portNumber) {
- synchronized (mReceivers) {
- if (mReceivers[portNumber] == null) {
- mReceivers[portNumber] = new ArrayList<MidiReceiver>();
- }
- mReceivers[portNumber].add(receiver);
- if (mReceiverCount++ == 0) {
- mThread.start();
- }
- }
- }
-
- /* package */ void disconnect(MidiReceiver receiver, int portNumber) {
- synchronized (mReceivers) {
- ArrayList<MidiReceiver> receivers = mReceivers[portNumber];
- if (receivers != null && receivers.remove(receiver)) {
- mReceiverCount--;
- }
- }
- }
-
- /* package */ boolean open() {
- FileDescriptor fd = mParcelFileDescriptor.getFileDescriptor();
- try {
- mInputStream = new FileInputStream(fd);
- } catch (Exception e) {
- Log.e(TAG, "could not create mInputStream", e);
- return false;
- }
-
try {
- mOutputStream = new FileOutputStream(fd);
- } catch (Exception e) {
- Log.e(TAG, "could not create mOutputStream", e);
- return false;
- }
- return true;
- }
-
- /* package */ void close() {
- try {
- if (mInputStream != null) {
- mInputStream.close();
- }
- if (mOutputStream != null) {
- mOutputStream.close();
+ ParcelFileDescriptor pfd = mServer.openOutputPort(portNumber);
+ if (pfd == null) {
+ return null;
}
- mParcelFileDescriptor.close();
- } catch (IOException e) {
+ return new MidiOutputPort(pfd, portNumber);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openOutputPort");
+ return null;
}
}
- /**
- * Returns a {@link MidiDeviceInfo} object, which describes this device.
- *
- * @return the {@link MidiDeviceInfo} object
- */
- public MidiDeviceInfo getInfo() {
- return mDeviceInfo;
- }
-
@Override
public String toString() {
- return ("MidiDevice: " + mDeviceInfo.toString() + " fd: " + mParcelFileDescriptor);
- }
-
- public static final Parcelable.Creator<MidiDevice> CREATOR =
- new Parcelable.Creator<MidiDevice>() {
- public MidiDevice createFromParcel(Parcel in) {
- MidiDeviceInfo deviceInfo = (MidiDeviceInfo)in.readParcelable(null);
- ParcelFileDescriptor pfd = (ParcelFileDescriptor)in.readParcelable(null);
- return new MidiDevice(deviceInfo, pfd);
- }
-
- public MidiDevice[] newArray(int size) {
- return new MidiDevice[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeParcelable(mDeviceInfo, flags);
- parcel.writeParcelable(mParcelFileDescriptor, flags);
- }
-
- /**
- * Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor
- *
- * message byte array contains variable length MIDI message.
- * messageSize is size of variable length MIDI message
- * timestamp is message timestamp to pack
- * dest is buffer to pack into
- * returns size of packed message
- *
- * @hide
- */
- public static int packMessage(byte[] message, int offset, int size, long timestamp,
- int portNumber, byte[] dest) {
- // pack variable length message first
- System.arraycopy(message, offset, dest, 0, size);
- int destOffset = size;
- // timestamp takes 8 bytes
- for (int i = 0; i < 8; i++) {
- dest[destOffset++] = (byte)timestamp;
- timestamp >>= 8;
- }
- // portNumber is last
- dest[destOffset++] = (byte)portNumber;
-
- return destOffset;
- }
-
- /**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * returns the offet of of MIDI message in packed buffer
- *
- * @hide
- */
- public static int getMessageOffset(byte[] buffer, int bufferLength) {
- // message is at start of buffer
- return 0;
- }
-
- /**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * returns size of MIDI message in packed buffer
- *
- * @hide
- */
- public static int getMessageSize(byte[] buffer, int bufferLength) {
- // message length is total buffer length minus size of the timestamp and port number
- return bufferLength - 9 /* (sizeof(timestamp) + sizeof(portNumber)) */;
+ return ("MidiDevice: " + mDeviceInfo.toString());
}
-
- /**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * unpacks timestamp from packed buffer
- *
- * @hide
- */
- public static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
- long timestamp = 0;
-
- // timestamp follows variable length message data
- int dataLength = getMessageSize(buffer, bufferLength);
- for (int i = dataLength + 7; i >= dataLength; i--) {
- // why can't Java deal with unsigned ints?
- int b = buffer[i];
- if (b < 0) b += 256;
- timestamp = (timestamp << 8) | b;
- }
- return timestamp;
- }
-
- /**
- * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
- * unpacks port number from packed buffer
- *
- * @hide
- */
- public static int getMessagePortNumber(byte[] buffer, int bufferLength) {
- // timestamp follows variable length message data and timestamp
- int dataLength = getMessageSize(buffer, bufferLength);
- return buffer[dataLength + 8 /* sizeof(timestamp) */];
- }
}
diff --git a/core/java/android/midi/MidiDeviceInfo.java b/core/java/android/midi/MidiDeviceInfo.java
index 5b57696..5cf62b5 100644
--- a/core/java/android/midi/MidiDeviceInfo.java
+++ b/core/java/android/midi/MidiDeviceInfo.java
@@ -50,10 +50,6 @@ public class MidiDeviceInfo implements Parcelable {
private final int mOutputPortCount;
private final Bundle mProperties;
- // used for USB devices only
- private final int mAlsaCard;
- private final int mAlsaDevice;
-
/**
* Bundle key for the device's manufacturer name property.
* Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
@@ -83,33 +79,30 @@ public class MidiDeviceInfo implements Parcelable {
public static final String PROPERTY_USB_DEVICE = "usb_device";
/**
- * MidiDeviceInfo should only be instantiated by MidiService implementation
- * @hide
+ * Bundle key for the device's ALSA card number.
+ * Only set for USB MIDI devices.
+ * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
*/
- public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
- Bundle properties) {
- mType = type;
- mId = id;
- mInputPortCount = numInputPorts;
- mOutputPortCount = numOutputPorts;
- mProperties = properties;
- mAlsaCard = -1;
- mAlsaDevice = -1;
- }
+ public static final String PROPERTY_ALSA_CARD = "alsa_card";
+
+ /**
+ * Bundle key for the device's ALSA device number.
+ * Only set for USB MIDI devices.
+ * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+ */
+ public static final String PROPERTY_ALSA_DEVICE = "alsa_device";
/**
* MidiDeviceInfo should only be instantiated by MidiService implementation
* @hide
*/
public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
- Bundle properties, int alsaCard, int alsaDevice) {
+ Bundle properties) {
mType = type;
mId = id;
mInputPortCount = numInputPorts;
mOutputPortCount = numOutputPorts;
mProperties = properties;
- mAlsaCard = alsaCard;
- mAlsaDevice = alsaDevice;
}
/**
@@ -158,20 +151,6 @@ public class MidiDeviceInfo implements Parcelable {
return mProperties;
}
- /**
- * @hide
- */
- public int getAlsaCard() {
- return mAlsaCard;
- }
-
- /**
- * @hide
- */
- public int getAlsaDevice() {
- return mAlsaDevice;
- }
-
@Override
public boolean equals(Object o) {
if (o instanceof MidiDeviceInfo) {
@@ -191,9 +170,7 @@ public class MidiDeviceInfo implements Parcelable {
return ("MidiDeviceInfo[mType=" + mType +
",mInputPortCount=" + mInputPortCount +
",mOutputPortCount=" + mOutputPortCount +
- ",mProperties=" + mProperties +
- ",mAlsaCard=" + mAlsaCard +
- ",mAlsaDevice=" + mAlsaDevice);
+ ",mProperties=" + mProperties);
}
public static final Parcelable.Creator<MidiDeviceInfo> CREATOR =
@@ -204,9 +181,7 @@ public class MidiDeviceInfo implements Parcelable {
int inputPorts = in.readInt();
int outputPorts = in.readInt();
Bundle properties = in.readBundle();
- int card = in.readInt();
- int device = in.readInt();
- return new MidiDeviceInfo(type, id, inputPorts, outputPorts, properties, card, device);
+ return new MidiDeviceInfo(type, id, inputPorts, outputPorts, properties);
}
public MidiDeviceInfo[] newArray(int size) {
@@ -224,7 +199,5 @@ public class MidiDeviceInfo implements Parcelable {
parcel.writeInt(mInputPortCount);
parcel.writeInt(mOutputPortCount);
parcel.writeBundle(mProperties);
- parcel.writeInt(mAlsaCard);
- parcel.writeInt(mAlsaDevice);
}
}
diff --git a/core/java/android/midi/MidiDeviceServer.java b/core/java/android/midi/MidiDeviceServer.java
new file mode 100644
index 0000000..6ce4bf7
--- /dev/null
+++ b/core/java/android/midi/MidiDeviceServer.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.midi;
+
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.system.OsConstants;
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/** @hide */
+public final class MidiDeviceServer implements Closeable {
+ private static final String TAG = "MidiDeviceServer";
+
+ private final IMidiManager mMidiManager;
+
+ // MidiDeviceInfo for the device implemented by this server
+ private MidiDeviceInfo mDeviceInfo;
+ private int mInputPortCount;
+ private int mOutputPortCount;
+
+ // output ports for receiving messages from our clients
+ // we can have only one per port number
+ private MidiOutputPort[] mInputPortSenders;
+
+ // receivers attached to our input ports
+ private ArrayList<MidiReceiver>[] mInputPortReceivers;
+
+ // input ports for sending messages to our clients
+ // we can have multiple outputs per port number
+ private ArrayList<MidiInputPort>[] mOutputPortReceivers;
+
+ // subclass of MidiInputPort for passing to clients
+ // that notifies us when the connection has failed
+ private class ServerInputPort extends MidiInputPort {
+ ServerInputPort(ParcelFileDescriptor pfd, int portNumber) {
+ super(pfd, portNumber);
+ }
+
+ @Override
+ public void onIOException() {
+ synchronized (mOutputPortReceivers) {
+ mOutputPortReceivers[getPortNumber()] = null;
+ }
+ }
+ }
+
+ // subclass of MidiOutputPort for passing to clients
+ // that notifies us when the connection has failed
+ private class ServerOutputPort extends MidiOutputPort {
+ ServerOutputPort(ParcelFileDescriptor pfd, int portNumber) {
+ super(pfd, portNumber);
+ }
+
+ @Override
+ public void onIOException() {
+ synchronized (mInputPortSenders) {
+ mInputPortSenders[getPortNumber()] = null;
+ }
+ }
+ }
+
+ // Binder interface stub for receiving connection requests from clients
+ private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() {
+
+ @Override
+ public ParcelFileDescriptor openInputPort(int portNumber) {
+ if (portNumber < 0 || portNumber >= mInputPortCount) {
+ Log.e(TAG, "portNumber out of range in openInputPort: " + portNumber);
+ return null;
+ }
+
+ ParcelFileDescriptor result = null;
+ MidiOutputPort newOutputPort = null;
+
+ synchronized (mInputPortSenders) {
+ if (mInputPortSenders[portNumber] != null) {
+ Log.d(TAG, "port " + portNumber + " already open");
+ return null;
+ }
+
+ try {
+ ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
+ OsConstants.SOCK_SEQPACKET);
+ newOutputPort = new ServerOutputPort(pair[0], portNumber);
+ mInputPortSenders[portNumber] = newOutputPort;
+ result = pair[1];
+ } catch (IOException e) {
+ Log.e(TAG, "unable to create ParcelFileDescriptors in openInputPort");
+ return null;
+ }
+
+ if (newOutputPort != null) {
+ ArrayList<MidiReceiver> receivers = mInputPortReceivers[portNumber];
+ synchronized (receivers) {
+ for (int i = 0; i < receivers.size(); i++) {
+ newOutputPort.connect(receivers.get(i));
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public ParcelFileDescriptor openOutputPort(int portNumber) {
+ if (portNumber < 0 || portNumber >= mOutputPortCount) {
+ Log.e(TAG, "portNumber out of range in openOutputPort: " + portNumber);
+ return null;
+ }
+ synchronized (mOutputPortReceivers) {
+ try {
+ ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
+ OsConstants.SOCK_SEQPACKET);
+ mOutputPortReceivers[portNumber].add(new ServerInputPort(pair[0], portNumber));
+ return pair[1];
+ } catch (IOException e) {
+ Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
+ return null;
+ }
+ }
+ }
+ };
+
+ /* package */ MidiDeviceServer(IMidiManager midiManager) {
+ mMidiManager = midiManager;
+ }
+
+ /* package */ IMidiDeviceServer getBinderInterface() {
+ return mServer;
+ }
+
+ /* package */ void setDeviceInfo(MidiDeviceInfo deviceInfo) {
+ if (mDeviceInfo != null) {
+ throw new IllegalStateException("setDeviceInfo should only be called once");
+ }
+ mDeviceInfo = deviceInfo;
+ mInputPortCount = deviceInfo.getInputPortCount();
+ mOutputPortCount = deviceInfo.getOutputPortCount();
+ mInputPortSenders = new MidiOutputPort[mInputPortCount];
+
+ mInputPortReceivers = new ArrayList[mInputPortCount];
+ for (int i = 0; i < mInputPortCount; i++) {
+ mInputPortReceivers[i] = new ArrayList<MidiReceiver>();
+ }
+
+ mOutputPortReceivers = new ArrayList[mOutputPortCount];
+ for (int i = 0; i < mOutputPortCount; i++) {
+ mOutputPortReceivers[i] = new ArrayList<MidiInputPort>();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ // FIXME - close input and output ports too?
+ mMidiManager.unregisterDeviceServer(mServer);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in unregisterDeviceServer");
+ }
+ }
+
+ /**
+ * Returns a {@link MidiDeviceInfo} object, which describes this device.
+ *
+ * @return the {@link MidiDeviceInfo} object
+ */
+ public MidiDeviceInfo getInfo() {
+ return mDeviceInfo;
+ }
+
+ /**
+ * Called to open a {@link MidiSender} to allow receiving MIDI messages
+ * on the device's input port for the specified port number.
+ *
+ * @param portNumber the number of the input port
+ * @return the {@link MidiSender}
+ */
+ public MidiSender openInputPortSender(int portNumber) {
+ if (portNumber < 0 || portNumber >= mDeviceInfo.getInputPortCount()) {
+ throw new IllegalArgumentException("portNumber " + portNumber + " out of range");
+ }
+ final int portNumberF = portNumber;
+ return new MidiSender() {
+
+ @Override
+ public void connect(MidiReceiver receiver) {
+ // We always synchronize on mInputPortSenders before receivers if we need to
+ // synchronize on both.
+ synchronized (mInputPortSenders) {
+ ArrayList<MidiReceiver> receivers = mInputPortReceivers[portNumberF];
+ synchronized (receivers) {
+ receivers.add(receiver);
+ MidiOutputPort outputPort = mInputPortSenders[portNumberF];
+ if (outputPort != null) {
+ outputPort.connect(receiver);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void disconnect(MidiReceiver receiver) {
+ // We always synchronize on mInputPortSenders before receivers if we need to
+ // synchronize on both.
+ synchronized (mInputPortSenders) {
+ ArrayList<MidiReceiver> receivers = mInputPortReceivers[portNumberF];
+ synchronized (receivers) {
+ receivers.remove(receiver);
+ MidiOutputPort outputPort = mInputPortSenders[portNumberF];
+ if (outputPort != null) {
+ outputPort.disconnect(receiver);
+ }
+ }
+ }
+ }
+ };
+ }
+
+ /**
+ * Called to open a {@link MidiReceiver} to allow sending MIDI messages
+ * on the virtual device's output port for the specified port number.
+ *
+ * @param portNumber the number of the output port
+ * @return the {@link MidiReceiver}
+ */
+ public MidiReceiver openOutputPortReceiver(int portNumber) {
+ if (portNumber < 0 || portNumber >= mDeviceInfo.getOutputPortCount()) {
+ throw new IllegalArgumentException("portNumber " + portNumber + " out of range");
+ }
+ final int portNumberF = portNumber;
+ return new MidiReceiver() {
+
+ @Override
+ public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ ArrayList<MidiInputPort> receivers = mOutputPortReceivers[portNumberF];
+ synchronized (receivers) {
+ for (int i = 0; i < receivers.size(); i++) {
+ // FIXME catch errors and remove dead ones
+ receivers.get(i).onPost(msg, offset, count, timestamp);
+ }
+ }
+ }
+ };
+ }
+}
diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java
index 31449a5..5d806cf 100644
--- a/core/java/android/midi/MidiInputPort.java
+++ b/core/java/android/midi/MidiInputPort.java
@@ -16,6 +16,10 @@
package android.midi;
+import android.os.ParcelFileDescriptor;
+
+import libcore.io.IoUtils;
+
import java.io.FileOutputStream;
import java.io.IOException;
@@ -24,15 +28,16 @@ import java.io.IOException;
*
* @hide
*/
-public final class MidiInputPort extends MidiPort implements MidiReceiver {
+public class MidiInputPort extends MidiPort implements MidiReceiver {
private final FileOutputStream mOutputStream;
+
// buffer to use for sending messages out our output stream
- private final byte[] mBuffer = new byte[MidiDevice.MAX_PACKED_MESSAGE_SIZE];
+ private final byte[] mBuffer = new byte[MAX_PACKED_MESSAGE_SIZE];
- /* package */ MidiInputPort(FileOutputStream outputStream, int portNumber) {
+ /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
- mOutputStream = outputStream;
+ mOutputStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
}
/**
@@ -46,9 +51,20 @@ public final class MidiInputPort extends MidiPort implements MidiReceiver {
*/
public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
synchronized (mBuffer) {
- int length = MidiDevice.packMessage(msg, offset, count, timestamp, getPortNumber(),
- mBuffer);
- mOutputStream.write(mBuffer, 0, length);
+ int length = packMessage(msg, offset, count, timestamp, mBuffer);
+ try {
+ mOutputStream.write(mBuffer, 0, length);
+ } catch (IOException e) {
+ IoUtils.closeQuietly(mOutputStream);
+ // report I/O failure
+ onIOException();
+ throw e;
+ }
}
}
+
+ @Override
+ public void close() throws IOException {
+ mOutputStream.close();
+ }
}
diff --git a/core/java/android/midi/MidiManager.java b/core/java/android/midi/MidiManager.java
index 64cd4fe..2c1c7bf 100644
--- a/core/java/android/midi/MidiManager.java
+++ b/core/java/android/midi/MidiManager.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
@@ -146,40 +145,31 @@ public class MidiManager {
*/
public MidiDevice openDevice(MidiDeviceInfo deviceInfo) {
try {
- ParcelFileDescriptor pfd = mService.openDevice(mToken, deviceInfo);
- if (pfd == null) {
+ IMidiDeviceServer server = mService.openDevice(mToken, deviceInfo);
+ if (server == null) {
Log.e(TAG, "could not open device " + deviceInfo);
return null;
}
- MidiDevice device = new MidiDevice(deviceInfo, pfd);
- if (device.open()) {
- Log.d(TAG, "openDevice returning " + device);
- return device;
- }
+ return new MidiDevice(deviceInfo, server);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openDevice");
}
return null;
}
- /**
- * Creates a new MIDI virtual device.
- * NOTE: The method for creating virtual devices is likely to change before release.
- *
- * @param numInputPorts number of input ports for the virtual device
- * @param numOutputPorts number of output ports for the virtual device
- * @param properties a {@link android.os.Bundle} containing properties describing the device
- * @return a {@link MidiDevice} object to locally represent the device
- */
- public MidiDevice createVirtualDevice(int numInputPorts, int numOutputPorts,
- Bundle properties) {
+ /** @hide */
+ public MidiDeviceServer createDeviceServer(int numInputPorts, int numOutputPorts,
+ Bundle properties, boolean isPrivate, int type) {
try {
- MidiDevice device = mService.registerVirtualDevice(mToken,
- numInputPorts, numOutputPorts, properties);
- if (device != null && !device.open()) {
- device = null;
+ MidiDeviceServer server = new MidiDeviceServer(mService);
+ MidiDeviceInfo deviceInfo = mService.registerDeviceServer(server.getBinderInterface(),
+ numInputPorts, numOutputPorts, properties, isPrivate, type);
+ if (deviceInfo == null) {
+ Log.e(TAG, "registerVirtualDevice failed");
+ return null;
}
- return device;
+ server.setDeviceInfo(deviceInfo);
+ return server;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in createVirtualDevice");
return null;
@@ -187,16 +177,19 @@ public class MidiManager {
}
/**
- * Removes a MIDI virtual device.
+ * Creates a new MIDI virtual device.
*
- * @param device the {@link MidiDevice} for the virtual device to remove
+ * @param numInputPorts number of input ports for the virtual device
+ * @param numOutputPorts number of output ports for the virtual device
+ * @param properties a {@link android.os.Bundle} containing properties describing the device
+ * @param isPrivate true if this device should only be visible and accessible to apps
+ * with the same UID as the caller
+ * @return a {@link MidiVirtualDevice} object to locally represent the device
*/
- public void closeVirtualDevice(MidiDevice device) {
- try {
- device.close();
- mService.unregisterVirtualDevice(mToken, device.getInfo());
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in unregisterVirtualDevice");
- }
+ public MidiDeviceServer createDeviceServer(int numInputPorts, int numOutputPorts,
+ Bundle properties, boolean isPrivate) {
+ return createDeviceServer(numInputPorts, numOutputPorts, properties,
+ isPrivate, MidiDeviceInfo.TYPE_VIRTUAL);
}
+
}
diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java
index 7ce286b..8b2d65d 100644
--- a/core/java/android/midi/MidiOutputPort.java
+++ b/core/java/android/midi/MidiOutputPort.java
@@ -16,20 +16,88 @@
package android.midi;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
/**
* This class is used for receiving data to a port on a MIDI device
*
* @hide
*/
-public final class MidiOutputPort extends MidiPort implements MidiSender {
+public class MidiOutputPort extends MidiPort implements MidiSender {
+ private static final String TAG = "MidiOutputPort";
+
+ private final FileInputStream mInputStream;
+
+ // array of receiver lists, indexed by port number
+ private final ArrayList<MidiReceiver> mReceivers = new ArrayList<MidiReceiver>();
+
+ private int mReceiverCount; // total number of receivers for all ports
+
+ // This thread reads MIDI events from a socket and distributes them to the list of
+ // MidiReceivers attached to this device.
+ private final Thread mThread = new Thread() {
+ @Override
+ public void run() {
+ byte[] buffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+ ArrayList<MidiReceiver> deadReceivers = new ArrayList<MidiReceiver>();
- private final MidiDevice mDevice;
+ try {
+ while (true) {
+ // read next event
+ int count = mInputStream.read(buffer);
+ if (count < MIN_PACKED_MESSAGE_SIZE || count > MAX_PACKED_MESSAGE_SIZE) {
+ Log.e(TAG, "Number of bytes read out of range: " + count);
+ break;
+ }
- /* package */ MidiOutputPort(MidiDevice device, int portNumber) {
+ int offset = getMessageOffset(buffer, count);
+ int size = getMessageSize(buffer, count);
+ long timestamp = getMessageTimeStamp(buffer, count);
+
+ synchronized (mReceivers) {
+ for (int i = 0; i < mReceivers.size(); i++) {
+ MidiReceiver receiver = mReceivers.get(i);
+ try {
+ receiver.onPost(buffer, offset, size, timestamp);
+ } catch (IOException e) {
+ Log.e(TAG, "post failed");
+ deadReceivers.add(receiver);
+ }
+ }
+ // remove any receivers that failed
+ if (deadReceivers.size() > 0) {
+ for (MidiReceiver receiver: deadReceivers) {
+ mReceivers.remove(receiver);
+ mReceiverCount--;
+ }
+ deadReceivers.clear();
+ }
+ // exit if we have no receivers left
+ if (mReceiverCount == 0) {
+ break;
+ }
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "read failed");
+ // report I/O failure
+ IoUtils.closeQuietly(mInputStream);
+ onIOException();
+ }
+ }
+ };
+
+
+ /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
super(portNumber);
- mDevice = device;
+ mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
}
/**
@@ -39,7 +107,12 @@ public final class MidiOutputPort extends MidiPort implements MidiSender {
* @param receiver the receiver to connect
*/
public void connect(MidiReceiver receiver) {
- mDevice.connect(receiver, getPortNumber());
+ synchronized (mReceivers) {
+ mReceivers.add(receiver);
+ if (mReceiverCount++ == 0) {
+ mThread.start();
+ }
+ }
}
/**
@@ -48,6 +121,15 @@ public final class MidiOutputPort extends MidiPort implements MidiSender {
* @param receiver the receiver to connect
*/
public void disconnect(MidiReceiver receiver) {
- mDevice.disconnect(receiver, getPortNumber());
+ synchronized (mReceivers) {
+ if (mReceivers.remove(receiver)) {
+ mReceiverCount--;
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ mInputStream.close();
}
}
diff --git a/core/java/android/midi/MidiPort.java b/core/java/android/midi/MidiPort.java
index fdd0233..53cba21 100644
--- a/core/java/android/midi/MidiPort.java
+++ b/core/java/android/midi/MidiPort.java
@@ -16,8 +16,9 @@
package android.midi;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import android.util.Log;
+
+import java.io.Closeable;
/**
* This class represents a MIDI input or output port.
@@ -25,10 +26,24 @@ import java.io.IOException;
*
* @hide
*/
-public class MidiPort {
+abstract public class MidiPort implements Closeable {
+ private static final String TAG = "MidiPort";
private final int mPortNumber;
+ /**
+ * Minimum size of packed message as sent through our ParcelFileDescriptor
+ * 8 bytes for timestamp, 1 byte for port number and 1 to 3 bytes for message
+ */
+ protected static final int MIN_PACKED_MESSAGE_SIZE = 10;
+
+ /**
+ * Maximum size of packed message as sent through our ParcelFileDescriptor
+ * 8 bytes for timestamp, 1 byte for port number and 1 to 3 bytes for message
+ */
+ protected static final int MAX_PACKED_MESSAGE_SIZE = 12;
+
+
/* package */ MidiPort(int portNumber) {
mPortNumber = portNumber;
}
@@ -41,4 +56,69 @@ public class MidiPort {
public final int getPortNumber() {
return mPortNumber;
}
+
+ /**
+ * Called when an IOExeption occurs while sending or receiving data.
+ * Subclasses can override to be notified of such errors
+ *
+ */
+ public void onIOException() {
+ }
+
+ /**
+ * Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor
+ *
+ * message byte array contains variable length MIDI message.
+ * messageSize is size of variable length MIDI message
+ * timestamp is message timestamp to pack
+ * dest is buffer to pack into
+ * returns size of packed message
+ */
+ protected static int packMessage(byte[] message, int offset, int size, long timestamp,
+ byte[] dest) {
+ // pack variable length message first
+ System.arraycopy(message, offset, dest, 0, size);
+ int destOffset = size;
+ // timestamp takes 8 bytes
+ for (int i = 0; i < 8; i++) {
+ dest[destOffset++] = (byte)timestamp;
+ timestamp >>= 8;
+ }
+
+ return destOffset;
+ }
+
+ /**
+ * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * returns the offet of of MIDI message in packed buffer
+ */
+ protected static int getMessageOffset(byte[] buffer, int bufferLength) {
+ // message is at start of buffer
+ return 0;
+ }
+
+ /**
+ * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * returns size of MIDI message in packed buffer
+ */
+ protected static int getMessageSize(byte[] buffer, int bufferLength) {
+ // message length is total buffer length minus size of the timestamp and port number
+ return bufferLength - 8 /* sizeof(timestamp) */;
+ }
+
+ /**
+ * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * unpacks timestamp from packed buffer
+ */
+ protected static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+ long timestamp = 0;
+
+ // timestamp follows variable length message data
+ int dataLength = getMessageSize(buffer, bufferLength);
+ for (int i = dataLength + 7; i >= dataLength; i--) {
+ int b = (int)buffer[i] & 0xFF;
+ timestamp = (timestamp << 8) | b;
+ }
+ return timestamp;
+ }
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c0dca0e..cd45cfb 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -4083,7 +4083,7 @@ public abstract class BatteryStats implements Parcelable {
prepareForDumpLocked();
dumpLine(pw, 0 /* uid */, "i" /* category */, VERSION_DATA,
- "11", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion());
+ "12", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion());
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index b209690..23ddd03 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -91,7 +91,7 @@ public class Build {
/** The name of the hardware (from the kernel command line or /proc). */
public static final String HARDWARE = getString("ro.hardware");
- /** A hardware serial number, if available. Alphanumeric only, case-insensitive. */
+ /** A hardware serial number, if available. Alphanumeric only, case-insensitive. */
public static final String SERIAL = getString("ro.serialno");
/**
@@ -159,7 +159,7 @@ public class Build {
/**
* The user-visible SDK version of the framework in its raw String
* representation; use {@link #SDK_INT} instead.
- *
+ *
* @deprecated Use {@link #SDK_INT} to easily get this as an integer.
*/
@Deprecated
@@ -207,25 +207,25 @@ public class Build {
* not yet turned into an official release.
*/
public static final int CUR_DEVELOPMENT = 10000;
-
+
/**
* October 2008: The original, first, version of Android. Yay!
*/
public static final int BASE = 1;
-
+
/**
* February 2009: First Android update, officially called 1.1.
*/
public static final int BASE_1_1 = 2;
-
+
/**
* May 2009: Android 1.5.
*/
public static final int CUPCAKE = 3;
-
+
/**
* September 2009: Android 1.6.
- *
+ *
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -247,10 +247,10 @@ public class Build {
* </ul>
*/
public static final int DONUT = 4;
-
+
/**
* November 2009: Android 2.0
- *
+ *
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
@@ -267,22 +267,22 @@ public class Build {
* </ul>
*/
public static final int ECLAIR = 5;
-
+
/**
* December 2009: Android 2.0.1
*/
public static final int ECLAIR_0_1 = 6;
-
+
/**
* January 2010: Android 2.1
*/
public static final int ECLAIR_MR1 = 7;
-
+
/**
* June 2010: Android 2.2
*/
public static final int FROYO = 8;
-
+
/**
* November 2010: Android 2.3
*
@@ -294,7 +294,7 @@ public class Build {
* </ul>
*/
public static final int GINGERBREAD = 9;
-
+
/**
* February 2011: Android 2.3.3.
*/
@@ -339,12 +339,12 @@ public class Build {
* </ul>
*/
public static final int HONEYCOMB = 11;
-
+
/**
* May 2011: Android 3.1.
*/
public static final int HONEYCOMB_MR1 = 12;
-
+
/**
* June 2011: Android 3.2.
*
@@ -598,7 +598,7 @@ public class Build {
*/
public static final int LOLLIPOP_MR1 = 22;
}
-
+
/** The type of build, like "user" or "eng". */
public static final String TYPE = getString("ro.build.type");
@@ -653,6 +653,7 @@ public class Build {
public static boolean isFingerprintConsistent() {
final String system = SystemProperties.get("ro.build.fingerprint");
final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
+ final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
if (TextUtils.isEmpty(system)) {
Slog.e(TAG, "Required ro.build.fingerprint is empty!");
@@ -667,6 +668,14 @@ public class Build {
}
}
+ if (!TextUtils.isEmpty(bootimage)) {
+ if (!Objects.equals(vendor, bootimage)) {
+ Slog.e(TAG, "Mismatched fingerprints; system and vendor reported " + system
+ + " but bootimage reported " + bootimage);
+ return false;
+ }
+ }
+
return true;
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 6db5f67..63ccf64 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -174,8 +174,16 @@ public final class StrictMode {
*/
public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
+ /**
+ * For StrictMode.noteResourceMismatch()
+ *
+ * @hide
+ */
+ public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
+
private static final int ALL_THREAD_DETECT_BITS =
- DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM;
+ DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM |
+ DETECT_RESOURCE_MISMATCH;
// Process-policy:
@@ -430,6 +438,22 @@ public final class StrictMode {
}
/**
+ * Disable detection of mismatches between defined resource types
+ * and getter calls.
+ */
+ public Builder permitResourceMismatches() {
+ return disable(DETECT_RESOURCE_MISMATCH);
+ }
+
+ /**
+ * Enable detection of mismatches between defined resource types
+ * and getter calls.
+ */
+ public Builder detectResourceMismatches() {
+ return enable(DETECT_RESOURCE_MISMATCH);
+ }
+
+ /**
* Enable detection of disk writes.
*/
public Builder detectDiskWrites() {
@@ -851,6 +875,15 @@ public final class StrictMode {
}
/**
+ * @hide
+ */
+ private static class StrictModeResourceMismatchViolation extends StrictModeViolation {
+ public StrictModeResourceMismatchViolation(int policyMask, Object tag) {
+ super(policyMask, DETECT_RESOURCE_MISMATCH, tag != null ? tag.toString() : null);
+ }
+ }
+
+ /**
* Returns the bitmask of the current thread's policy.
*
* @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
@@ -1125,6 +1158,20 @@ public final class StrictMode {
startHandlingViolationException(e);
}
+ // Not part of BlockGuard.Policy; just part of StrictMode:
+ void onResourceMismatch(Object tag) {
+ if ((mPolicyMask & DETECT_RESOURCE_MISMATCH) == 0) {
+ return;
+ }
+ if (tooManyViolationsThisLoop()) {
+ return;
+ }
+ BlockGuard.BlockGuardPolicyException e =
+ new StrictModeResourceMismatchViolation(mPolicyMask, tag);
+ e.fillInStackTrace();
+ startHandlingViolationException(e);
+ }
+
// Part of BlockGuard.Policy interface:
public void onReadFromDisk() {
if ((mPolicyMask & DETECT_DISK_READ) == 0) {
@@ -1943,6 +1990,26 @@ public final class StrictMode {
}
/**
+ * For code to note that a resource was obtained using a type other than
+ * its defined type. This is a no-op unless the current thread's
+ * {@link android.os.StrictMode.ThreadPolicy} has
+ * {@link android.os.StrictMode.ThreadPolicy.Builder#detectResourceMismatches()}
+ * enabled.
+ *
+ * @param tag an object for the exception stack trace that's
+ * built if when this fires.
+ * @hide
+ */
+ public static void noteResourceMismatch(Object tag) {
+ BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+ if (!(policy instanceof AndroidBlockGuardPolicy)) {
+ // StrictMode not enabled.
+ return;
+ }
+ ((AndroidBlockGuardPolicy) policy).onResourceMismatch(tag);
+ }
+
+ /**
* @hide
*/
public static void noteDiskRead() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ffbed94..d124a49 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -56,6 +56,7 @@ public class UserManager {
/**
* Specifies if a user is disallowed from changing Wi-Fi
* access points. The default value is <code>false</code>.
+ * <p/>This restriction has no effect in a managed profile.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -87,8 +88,10 @@ public class UserManager {
public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
/**
- * Specifies if a user is disallowed from toggling location sharing.
+ * Specifies if a user is disallowed from turning on location sharing.
* The default value is <code>false</code>.
+ * <p/>In a managed profile, location sharing always reflects the primary user's setting, but
+ * can be overridden and forced off by setting this restriction to true in the managed profile.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -112,6 +115,7 @@ public class UserManager {
/**
* Specifies if a user is disallowed from configuring bluetooth.
* The default value is <code>false</code>.
+ * <p/>This restriction has no effect in a managed profile.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -144,8 +148,10 @@ public class UserManager {
public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
/**
- * Specifies if a user is disallowed from removing itself and other
- * users. The default value is <code>false</code>.
+ * When set on the primary user this specifies if the user can remove other users.
+ * When set on a secondary user, this specifies if the user can remove itself.
+ * This restriction has no effect on managed profiles.
+ * The default value is <code>false</code>.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -168,6 +174,7 @@ public class UserManager {
/**
* Specifies if a user is disallowed from configuring VPN.
* The default value is <code>false</code>.
+ * This restriction has no effect in a managed profile.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -192,6 +199,8 @@ public class UserManager {
* Specifies if a user is disallowed from factory resetting
* from Settings. This can only be set by device owners and profile owners on the primary user.
* The default value is <code>false</code>.
+ * <p/>This restriction has no effect on secondary users and managed profiles since only the
+ * primary user can factory reset the device.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -204,6 +213,8 @@ public class UserManager {
* Specifies if a user is disallowed from adding new users and
* profiles. This can only be set by device owners and profile owners on the primary user.
* The default value is <code>false</code>.
+ * <p/>This restriction has no effect on secondary users and managed profiles since only the
+ * primary user can add other users.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -227,6 +238,8 @@ public class UserManager {
* Specifies if a user is disallowed from configuring cell
* broadcasts. This can only be set by device owners and profile owners on the primary user.
* The default value is <code>false</code>.
+ * <p/>This restriction has no effect on secondary users and managed profiles since only the
+ * primary user can configure cell broadcasts.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -239,6 +252,8 @@ public class UserManager {
* Specifies if a user is disallowed from configuring mobile
* networks. This can only be set by device owners and profile owners on the primary user.
* The default value is <code>false</code>.
+ * <p/>This restriction has no effect on secondary users and managed profiles since only the
+ * primary user can configure mobile networks.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -307,6 +322,8 @@ public class UserManager {
* Specifies that the user is not allowed to make outgoing
* phone calls. Emergency calls are still permitted.
* The default value is <code>false</code>.
+ * <p/>This restriction has no effect on managed profiles since call intents are normally
+ * forwarded to the primary user.
*
* <p/>Key for user restrictions.
* <p/>Type: Boolean
@@ -383,8 +400,10 @@ public class UserManager {
*
* <p/>Key for application restrictions.
* <p/>Type: Boolean
- * @see android.app.admin.DevicePolicyManager#setApplicationRestrictions()
- * @see android.app.admin.DevicePolicyManager#getApplicationRestrictions()
+ * @see android.app.admin.DevicePolicyManager#setApplicationRestrictions(
+ * android.content.ComponentName, String, Bundle)
+ * @see android.app.admin.DevicePolicyManager#getApplicationRestrictions(
+ * android.content.ComponentName, String)
*/
public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 69c81f8..687db7c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3657,6 +3657,7 @@ public final class Settings {
* A flag containing settings used for biometric weak
* @hide
*/
+ @Deprecated
public static final String LOCK_BIOMETRIC_WEAK_FLAGS =
"lock_biometric_weak_flags";
@@ -3668,7 +3669,11 @@ public final class Settings {
/**
* Whether autolock is enabled (0 = false, 1 = true)
+ *
+ * @deprecated Use {@link android.app.KeyguardManager} to determine the state and security
+ * level of the keyguard.
*/
+ @Deprecated
public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
/**
@@ -3707,6 +3712,7 @@ public final class Settings {
* Ids of the user-selected appwidgets on the lockscreen (comma-delimited).
* @hide
*/
+ @Deprecated
public static final String LOCK_SCREEN_APPWIDGET_IDS =
"lock_screen_appwidget_ids";
@@ -3720,6 +3726,7 @@ public final class Settings {
* Id of the appwidget shown on the lock screen when appwidgets are disabled.
* @hide
*/
+ @Deprecated
public static final String LOCK_SCREEN_FALLBACK_APPWIDGET_ID =
"lock_screen_fallback_appwidget_id";
@@ -3727,6 +3734,7 @@ public final class Settings {
* Index of the lockscreen appwidget to restore, -1 if none.
* @hide
*/
+ @Deprecated
public static final String LOCK_SCREEN_STICKY_APPWIDGET =
"lock_screen_sticky_appwidget";
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
new file mode 100644
index 0000000..bf51ed1
--- /dev/null
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.security.KeystoreArguments;
+
+/**
+ * This must be kept manually in sync with system/security/keystore until AIDL
+ * can generate both Java and C++ bindings.
+ *
+ * @hide
+ */
+interface IKeystoreService {
+ int test();
+ byte[] get(String name);
+ int insert(String name, in byte[] item, int uid, int flags);
+ int del(String name, int uid);
+ int exist(String name, int uid);
+ String[] saw(String namePrefix, int uid);
+ int reset();
+ int password(String password);
+ int lock();
+ int unlock(String password);
+ int zero();
+ int generate(String name, int uid, int keyType, int keySize, int flags,
+ in KeystoreArguments args);
+ int import_key(String name, in byte[] data, int uid, int flags);
+ byte[] sign(String name, in byte[] data);
+ int verify(String name, in byte[] data, in byte[] signature);
+ byte[] get_pubkey(String name);
+ int del_key(String name, int uid);
+ int grant(String name, int granteeUid);
+ int ungrant(String name, int granteeUid);
+ long getmtime(String name);
+ int duplicate(String srcKey, int srcUid, String destKey, int destUid);
+ int is_hardware_backed(String string);
+ int clear_uid(long uid);
+ int reset_uid(int uid);
+ int sync_uid(int sourceUid, int targetUid);
+ int password_uid(String password, int uid);
+}
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
deleted file mode 100644
index 7e9aba0..0000000
--- a/core/java/android/security/IKeystoreService.java
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.RemoteException;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-public interface IKeystoreService extends IInterface {
- public static abstract class Stub extends Binder implements IKeystoreService {
- private static class Proxy implements IKeystoreService {
- private final IBinder mRemote;
-
- Proxy(IBinder remote) {
- mRemote = remote;
- }
-
- public IBinder asBinder() {
- return mRemote;
- }
-
- public String getInterfaceDescriptor() {
- return DESCRIPTOR;
- }
-
- public int test() throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public byte[] get(String name) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- byte[] _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- mRemote.transact(Stub.TRANSACTION_get, _data, _reply, 0);
- _reply.readException();
- _result = _reply.createByteArray();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int insert(String name, byte[] item, int uid, int flags) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeByteArray(item);
- _data.writeInt(uid);
- _data.writeInt(flags);
- mRemote.transact(Stub.TRANSACTION_insert, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int del(String name, int uid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeInt(uid);
- mRemote.transact(Stub.TRANSACTION_del, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int exist(String name, int uid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeInt(uid);
- mRemote.transact(Stub.TRANSACTION_exist, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public String[] saw(String name, int uid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- String[] _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeInt(uid);
- mRemote.transact(Stub.TRANSACTION_saw, _data, _reply, 0);
- _reply.readException();
- int size = _reply.readInt();
- _result = new String[size];
- for (int i = 0; i < size; i++) {
- _result[i] = _reply.readString();
- }
- int _ret = _reply.readInt();
- if (_ret != 1) {
- return null;
- }
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- @Override
- public int reset() throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_reset, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int password(String password) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(password);
- mRemote.transact(Stub.TRANSACTION_password, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int lock() throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_lock, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int unlock(String password) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(password);
- mRemote.transact(Stub.TRANSACTION_unlock, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- @Override
- public int zero() throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_zero, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int generate(String name, int uid, int keyType, int keySize, int flags,
- byte[][] args) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeInt(uid);
- _data.writeInt(keyType);
- _data.writeInt(keySize);
- _data.writeInt(flags);
- if (args == null) {
- _data.writeInt(0);
- } else {
- _data.writeInt(args.length);
- for (int i = 0; i < args.length; i++) {
- _data.writeByteArray(args[i]);
- }
- }
- mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int import_key(String name, byte[] data, int uid, int flags)
- throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeByteArray(data);
- _data.writeInt(uid);
- _data.writeInt(flags);
- mRemote.transact(Stub.TRANSACTION_import, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public byte[] sign(String name, byte[] data) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- byte[] _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeByteArray(data);
- mRemote.transact(Stub.TRANSACTION_sign, _data, _reply, 0);
- _reply.readException();
- _result = _reply.createByteArray();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int verify(String name, byte[] data, byte[] signature) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeByteArray(data);
- _data.writeByteArray(signature);
- mRemote.transact(Stub.TRANSACTION_verify, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public byte[] get_pubkey(String name) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- byte[] _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- mRemote.transact(Stub.TRANSACTION_get_pubkey, _data, _reply, 0);
- _reply.readException();
- _result = _reply.createByteArray();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int del_key(String name, int uid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeInt(uid);
- mRemote.transact(Stub.TRANSACTION_del_key, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int grant(String name, int granteeUid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeInt(granteeUid);
- mRemote.transact(Stub.TRANSACTION_grant, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int ungrant(String name, int granteeUid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- _data.writeInt(granteeUid);
- mRemote.transact(Stub.TRANSACTION_ungrant, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- @Override
- public long getmtime(String name) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- long _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(name);
- mRemote.transact(Stub.TRANSACTION_getmtime, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readLong();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- @Override
- public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
- throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(srcKey);
- _data.writeInt(srcUid);
- _data.writeString(destKey);
- _data.writeInt(destUid);
- mRemote.transact(Stub.TRANSACTION_duplicate, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- @Override
- public int is_hardware_backed(String keyType) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(keyType);
- mRemote.transact(Stub.TRANSACTION_is_hardware_backed, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- @Override
- public int clear_uid(long uid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeLong(uid);
- mRemote.transact(Stub.TRANSACTION_clear_uid, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int reset_uid(int uid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeInt(uid);
- mRemote.transact(Stub.TRANSACTION_reset_uid, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int sync_uid(int srcUid, int dstUid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeInt(srcUid);
- _data.writeInt(dstUid);
- mRemote.transact(Stub.TRANSACTION_sync_uid, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
-
- public int password_uid(String password, int uid) throws RemoteException {
- Parcel _data = Parcel.obtain();
- Parcel _reply = Parcel.obtain();
- int _result;
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- _data.writeString(password);
- _data.writeInt(uid);
- mRemote.transact(Stub.TRANSACTION_password_uid, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
- }
-
- private static final String DESCRIPTOR = "android.security.keystore";
-
- static final int TRANSACTION_test = IBinder.FIRST_CALL_TRANSACTION + 0;
- static final int TRANSACTION_get = IBinder.FIRST_CALL_TRANSACTION + 1;
- static final int TRANSACTION_insert = IBinder.FIRST_CALL_TRANSACTION + 2;
- static final int TRANSACTION_del = IBinder.FIRST_CALL_TRANSACTION + 3;
- static final int TRANSACTION_exist = IBinder.FIRST_CALL_TRANSACTION + 4;
- static final int TRANSACTION_saw = IBinder.FIRST_CALL_TRANSACTION + 5;
- static final int TRANSACTION_reset = IBinder.FIRST_CALL_TRANSACTION + 6;
- static final int TRANSACTION_password = IBinder.FIRST_CALL_TRANSACTION + 7;
- static final int TRANSACTION_lock = IBinder.FIRST_CALL_TRANSACTION + 8;
- static final int TRANSACTION_unlock = IBinder.FIRST_CALL_TRANSACTION + 9;
- static final int TRANSACTION_zero = IBinder.FIRST_CALL_TRANSACTION + 10;
- static final int TRANSACTION_generate = IBinder.FIRST_CALL_TRANSACTION + 11;
- static final int TRANSACTION_import = IBinder.FIRST_CALL_TRANSACTION + 12;
- static final int TRANSACTION_sign = IBinder.FIRST_CALL_TRANSACTION + 13;
- static final int TRANSACTION_verify = IBinder.FIRST_CALL_TRANSACTION + 14;
- static final int TRANSACTION_get_pubkey = IBinder.FIRST_CALL_TRANSACTION + 15;
- static final int TRANSACTION_del_key = IBinder.FIRST_CALL_TRANSACTION + 16;
- static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17;
- static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
- static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
- static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20;
- static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21;
- static final int TRANSACTION_clear_uid = IBinder.FIRST_CALL_TRANSACTION + 22;
- static final int TRANSACTION_reset_uid = IBinder.FIRST_CALL_TRANSACTION + 23;
- static final int TRANSACTION_sync_uid = IBinder.FIRST_CALL_TRANSACTION + 24;
- static final int TRANSACTION_password_uid = IBinder.FIRST_CALL_TRANSACTION + 25;
-
- /**
- * Cast an IBinder object into an IKeystoreService interface, generating
- * a proxy if needed.
- */
- public static IKeystoreService asInterface(IBinder obj) {
- if (obj == null) {
- return null;
- }
- IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
- if (iin != null && iin instanceof IKeystoreService) {
- return (IKeystoreService) iin;
- }
- return new IKeystoreService.Stub.Proxy(obj);
- }
-
- /** Construct the stub at attach it to the interface. */
- public Stub() {
- attachInterface(this, DESCRIPTOR);
- }
-
- public IBinder asBinder() {
- return this;
- }
-
- @Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- switch (code) {
- case INTERFACE_TRANSACTION: {
- reply.writeString(DESCRIPTOR);
- return true;
- }
- case TRANSACTION_test: {
- data.enforceInterface(DESCRIPTOR);
- int resultCode = test();
- reply.writeNoException();
- reply.writeInt(resultCode);
- return true;
- }
- }
- return super.onTransact(code, data, reply, flags);
- }
- }
-
- public int test() throws RemoteException;
-
- public byte[] get(String name) throws RemoteException;
-
- public int insert(String name, byte[] item, int uid, int flags) throws RemoteException;
-
- public int del(String name, int uid) throws RemoteException;
-
- public int exist(String name, int uid) throws RemoteException;
-
- public String[] saw(String name, int uid) throws RemoteException;
-
- public int reset() throws RemoteException;
-
- public int password(String password) throws RemoteException;
-
- public int lock() throws RemoteException;
-
- public int unlock(String password) throws RemoteException;
-
- public int zero() throws RemoteException;
-
- public int generate(String name, int uid, int keyType, int keySize, int flags, byte[][] args)
- throws RemoteException;
-
- public int import_key(String name, byte[] data, int uid, int flags) throws RemoteException;
-
- public byte[] sign(String name, byte[] data) throws RemoteException;
-
- public int verify(String name, byte[] data, byte[] signature) throws RemoteException;
-
- public byte[] get_pubkey(String name) throws RemoteException;
-
- public int del_key(String name, int uid) throws RemoteException;
-
- public int grant(String name, int granteeUid) throws RemoteException;
-
- public int ungrant(String name, int granteeUid) throws RemoteException;
-
- public long getmtime(String name) throws RemoteException;
-
- public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
- throws RemoteException;
-
- public int is_hardware_backed(String string) throws RemoteException;
-
- public int clear_uid(long uid) throws RemoteException;
-
- public int reset_uid(int uid) throws RemoteException;
-
- public int sync_uid(int sourceUid, int targetUid) throws RemoteException;
-
- public int password_uid(String password, int uid) throws RemoteException;
-}
diff --git a/core/java/android/midi/MidiDevice.aidl b/core/java/android/security/KeystoreArguments.aidl
index 11bb497..d636414 100644
--- a/core/java/android/midi/MidiDevice.aidl
+++ b/core/java/android/security/KeystoreArguments.aidl
@@ -1,5 +1,5 @@
-/*
- * Copyright (C) 2014, The Android Open Source Project
+/**
+ * Copyright (c) 2015, 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.
@@ -14,6 +14,7 @@
* limitations under the License.
*/
-package android.midi;
+package android.security;
-parcelable MidiDevice;
+/* @hide */
+parcelable KeystoreArguments;
diff --git a/core/java/android/security/KeystoreArguments.java b/core/java/android/security/KeystoreArguments.java
new file mode 100644
index 0000000..16054e5
--- /dev/null
+++ b/core/java/android/security/KeystoreArguments.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Class for handling the additional arguments to some keystore binder calls.
+ * This must be kept in sync with the deserialization code in system/security/keystore.
+ * @hide
+ */
+public class KeystoreArguments implements Parcelable {
+ public byte[][] args;
+
+ public static final Parcelable.Creator<KeystoreArguments> CREATOR = new
+ Parcelable.Creator<KeystoreArguments>() {
+ public KeystoreArguments createFromParcel(Parcel in) {
+ return new KeystoreArguments(in);
+ }
+ public KeystoreArguments[] newArray(int size) {
+ return new KeystoreArguments[size];
+ }
+ };
+
+ public KeystoreArguments() {
+ args = null;
+ }
+
+ public KeystoreArguments(byte[][] args) {
+ this.args = args;
+ }
+
+ private KeystoreArguments(Parcel in) {
+ readFromParcel(in);
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ if (args == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(args.length);
+ for (byte[] arg : args) {
+ out.writeByteArray(arg);
+ }
+ }
+ }
+
+ private void readFromParcel(Parcel in) {
+ int length = in.readInt();
+ args = new byte[length][];
+ for (int i = 0; i < length; i++) {
+ args[i] = in.createByteArray();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d867adf..f486e0e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8121,6 +8121,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Report an accessibility action to this view's parents for delegated processing.
+ *
+ * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally
+ * call this method to delegate an accessibility action to a supporting parent. If the parent
+ * returns true from its
+ * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)}
+ * method this method will return true to signify that the action was consumed.</p>
+ *
+ * <p>This method is useful for implementing nested scrolling child views. If
+ * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action
+ * a custom view implementation may invoke this method to allow a parent to consume the
+ * scroll first. If this method returns true the custom view should skip its own scrolling
+ * behavior.</p>
+ *
+ * @param action Accessibility action to delegate
+ * @param arguments Optional action arguments
+ * @return true if the action was consumed by a parent
+ */
+ public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) {
+ for (ViewParent p = getParent(); p != null; p = p.getParent()) {
+ if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Performs the specified accessibility action on the view. For
* possible accessibility actions look at {@link AccessibilityNodeInfo}.
* <p>
@@ -8130,6 +8158,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* is responsible for handling this call.
* </p>
*
+ * <p>The default implementation will delegate
+ * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and
+ * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if
+ * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p>
+ *
* @param action The action to perform.
* @param arguments Optional action arguments.
* @return Whether the action was performed.
@@ -8150,6 +8183,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+ if (isNestedScrollingEnabled()
+ && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
+ || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)) {
+ if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) {
+ return true;
+ }
+ }
+
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK: {
if (isClickable()) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 71c79fd..d03e098 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -32,6 +32,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
+import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -2928,6 +2929,22 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* {@inheritDoc}
+ *
+ * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
+ *
+ * @param target The target view dispatching this action
+ * @param action Action being performed; see
+ * {@link android.view.accessibility.AccessibilityNodeInfo}
+ * @param args Optional action arguments
+ * @return false by default. Subclasses should return true if they handle the event.
+ */
+ @Override
+ public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
*/
@Override
void dispatchDetachedFromWindow() {
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 87a37f4..035871d 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -17,6 +17,7 @@
package android.view;
import android.graphics.Rect;
+import android.os.Bundle;
import android.view.accessibility.AccessibilityEvent;
/**
@@ -551,4 +552,23 @@ public interface ViewParent {
* @return true if this parent consumed the fling ahead of the target view
*/
public boolean onNestedPreFling(View target, float velocityX, float velocityY);
+
+ /**
+ * React to an accessibility action delegated by a target descendant view before the target
+ * processes it.
+ *
+ * <p>This method may be called by a target descendant view if the target wishes to give
+ * a view in its parent chain a chance to react to the event before normal processing occurs.
+ * Most commonly this will be a scroll event such as
+ * {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_SCROLL_FORWARD}.
+ * A ViewParent that supports acting as a nested scrolling parent should override this
+ * method and act accordingly to implement scrolling via accesibility systems.</p>
+ *
+ * @param target The target view dispatching this action
+ * @param action Action being performed; see
+ * {@link android.view.accessibility.AccessibilityNodeInfo}
+ * @param arguments Optional action arguments
+ * @return true if the action was consumed by this ViewParent
+ */
+ public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 34c27d7..87d9a58 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -560,39 +560,43 @@ public final class ViewRootImpl implements ViewParent,
case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
throw new WindowManager.BadTokenException(
- "Unable to add window -- token " + attrs.token
- + " is not valid; is your activity running?");
+ "Unable to add window -- token " + attrs.token
+ + " is not valid; is your activity running?");
case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
throw new WindowManager.BadTokenException(
- "Unable to add window -- token " + attrs.token
- + " is not for an application");
+ "Unable to add window -- token " + attrs.token
+ + " is not for an application");
case WindowManagerGlobal.ADD_APP_EXITING:
throw new WindowManager.BadTokenException(
- "Unable to add window -- app for token " + attrs.token
- + " is exiting");
+ "Unable to add window -- app for token " + attrs.token
+ + " is exiting");
case WindowManagerGlobal.ADD_DUPLICATE_ADD:
throw new WindowManager.BadTokenException(
- "Unable to add window -- window " + mWindow
- + " has already been added");
+ "Unable to add window -- window " + mWindow
+ + " has already been added");
case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
// Silently ignore -- we would have just removed it
// right away, anyway.
return;
case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
throw new WindowManager.BadTokenException(
- "Unable to add window " + mWindow +
- " -- another window of this type already exists");
+ "Unable to add window " + mWindow +
+ " -- another window of this type already exists");
case WindowManagerGlobal.ADD_PERMISSION_DENIED:
throw new WindowManager.BadTokenException(
- "Unable to add window " + mWindow +
- " -- permission denied for this window type");
+ "Unable to add window " + mWindow +
+ " -- permission denied for this window type");
case WindowManagerGlobal.ADD_INVALID_DISPLAY:
throw new WindowManager.InvalidDisplayException(
- "Unable to add window " + mWindow +
- " -- the specified display can not be found");
+ "Unable to add window " + mWindow +
+ " -- the specified display can not be found");
+ case WindowManagerGlobal.ADD_INVALID_TYPE:
+ throw new WindowManager.InvalidDisplayException(
+ "Unable to add window " + mWindow
+ + " -- the specified window type is not valid");
}
throw new RuntimeException(
- "Unable to add window -- unknown error code " + res);
+ "Unable to add window -- unknown error code " + res);
}
if (view instanceof RootViewSurfaceTaker) {
@@ -6413,6 +6417,11 @@ public final class ViewRootImpl implements ViewParent,
return false;
}
+ @Override
+ public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
+ return false;
+ }
+
void changeCanvasOpacity(boolean opaque) {
Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
if (mAttachInfo.mHardwareRenderer != null) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 55c6cb89..3f2f3a5 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -156,7 +156,10 @@ public abstract class Window {
public static final String NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME =
"android:navigation:background";
- /** The default features enabled */
+ /**
+ * The default features enabled.
+ * @deprecated use {@link #getDefaultFeatures(android.content.Context)} instead.
+ */
@Deprecated
@SuppressWarnings({"PointlessBitwiseExpression"})
protected static final int DEFAULT_FEATURES = (1 << FEATURE_OPTIONS_PANEL) |
@@ -1087,6 +1090,10 @@ public abstract class Window {
/**
* Sets the window elevation.
+ * <p>
+ * Changes to this property take effect immediately and will cause the
+ * window surface to be recreated. This is an expensive operation and as a
+ * result, this property should not be animated.
*
* @param elevation The window elevation.
* @see View#setElevation(float)
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 0d3727b..ed17e3f 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -103,6 +103,7 @@ public final class WindowManagerGlobal {
public static final int ADD_MULTIPLE_SINGLETON = -7;
public static final int ADD_PERMISSION_DENIED = -8;
public static final int ADD_INVALID_DISPLAY = -9;
+ public static final int ADD_INVALID_TYPE = -10;
private static WindowManagerGlobal sDefaultWindowManager;
private static IWindowManager sWindowManagerService;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 92ca427..6d3b063 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.UndoManager;
import android.content.res.ColorStateList;
import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -526,6 +527,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private final TextPaint mTextPaint;
private boolean mUserSetTextScaleX;
private Layout mLayout;
+ private boolean mLocaleChanged = false;
private int mGravity = Gravity.TOP | Gravity.START;
private boolean mHorizontallyScrolling;
@@ -2740,9 +2742,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @see Paint#setTextLocale
*/
public void setTextLocale(Locale locale) {
+ mLocaleChanged = true;
mTextPaint.setTextLocale(locale);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (!mLocaleChanged) {
+ mTextPaint.setTextLocale(Locale.getDefault());
+ }
+ }
+
/**
* @return the size (in pixels) of the default text size in this TextView.
*/