Merge "Move binder magic from the Surface class to GraphicBuffer."
diff --git a/api/current.xml b/api/current.xml
index b0f0b14..61b7297 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2352,6 +2352,17 @@
visibility="public"
>
</field>
+<field name="alertDialogTheme"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843598"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="allContactsName"
type="int"
transient="false"
@@ -3617,6 +3628,17 @@
visibility="public"
>
</field>
+<field name="dialogTheme"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843597"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dialogTitle"
type="int"
transient="false"
@@ -28899,6 +28921,17 @@
visibility="public"
>
</field>
+<field name="COLUMN_LOCAL_FILENAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""local_filename""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="COLUMN_LOCAL_URI"
type="java.lang.String"
transient="false"
@@ -44007,6 +44040,17 @@
synchronized="false"
static="true"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCurrentSyncs"
+ return="java.util.List<android.content.SyncInfo>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -54150,6 +54194,34 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parcel" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
<field name="account"
type="android.accounts.Account"
transient="false"
@@ -69533,6 +69605,161 @@
>
</field>
</class>
+<class name="DrmErrorEvent"
+ extends="android.drm.DrmEvent"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DrmErrorEvent"
+ type="android.drm.DrmErrorEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uniqueId" type="int">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<field name="TYPE_DRM_INFO_ACQUISITION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2012"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_FINALIZE_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2010"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_INITIALIZE_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2009"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_NOT_SUPPORTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2003"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_NO_INTERNET_CONNECTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2005"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_OUT_OF_MEMORY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2004"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REGISTRATION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2006"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REMOVE_ALL_RIGHTS_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2011"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_ACQUISITION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2008"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_NOT_INSTALLED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2001"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_RENEWAL_NOT_ALLOWED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2002"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_UNREGISTRATION_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2007"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="DrmEvent"
extends="java.lang.Object"
abstract="false"
@@ -69588,6 +69815,105 @@
visibility="public"
>
</method>
+<field name="DRM_INFO_OBJECT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""drm_info_object""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DRM_INFO_STATUS_OBJECT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""drm_info_status_object""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_ALL_RIGHTS_REMOVED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1006"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_DRM_INFO_ACQUIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1007"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_FINALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1001"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_INITIALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1003"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_REGISTERED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1002"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_RIGHTS_ACQUIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1005"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_UNREGISTERED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1004"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="DrmInfo"
extends="java.lang.Object"
@@ -69731,6 +70057,17 @@
<parameter name="message" type="java.lang.String">
</parameter>
</constructor>
+<field name="TYPE_ACCOUNT_ALREADY_REGISTERED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT"
type="int"
transient="false"
@@ -69742,39 +70079,6 @@
visibility="public"
>
</field>
-<field name="TYPE_NOT_SUPPORTED"
- type="int"
- transient="false"
- volatile="false"
- value="6"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TYPE_NO_INTERNET_CONNECTION"
- type="int"
- transient="false"
- volatile="false"
- value="9"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TYPE_OUT_OF_MEMORY"
- type="int"
- transient="false"
- volatile="false"
- value="8"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="TYPE_REMOVE_RIGHTS"
type="int"
transient="false"
@@ -69797,33 +70101,11 @@
visibility="public"
>
</field>
-<field name="TYPE_RIGHTS_NOT_INSTALLED"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TYPE_RIGHTS_RENEWAL_NOT_ALLOWED"
- type="int"
- transient="false"
- volatile="false"
- value="5"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="TYPE_WAIT_FOR_RIGHTS"
type="int"
transient="false"
volatile="false"
- value="7"
+ value="4"
static="true"
final="true"
deprecated="not deprecated"
@@ -70084,7 +70366,7 @@
</parameter>
</constructor>
<method name="acquireDrmInfo"
- return="android.drm.DrmInfo"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -70111,6 +70393,21 @@
<parameter name="mimeType" type="java.lang.String">
</parameter>
</method>
+<method name="canHandle"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
<method name="checkRightsStatus"
return="int"
abstract="false"
@@ -70134,11 +70431,39 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="checkRightsStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="path" type="java.lang.String">
</parameter>
<parameter name="action" type="int">
</parameter>
</method>
+<method name="checkRightsStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
+</method>
<method name="closeConvertSession"
return="android.drm.DrmConvertedStatus"
abstract="false"
@@ -70193,6 +70518,21 @@
<parameter name="action" type="int">
</parameter>
</method>
+<method name="getConstraints"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
+</method>
<method name="getDrmObjectType"
return="int"
abstract="false"
@@ -70208,6 +70548,21 @@
<parameter name="mimeType" type="java.lang.String">
</parameter>
</method>
+<method name="getDrmObjectType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="mimeType" type="java.lang.String">
+</parameter>
+</method>
<method name="getOriginalMimeType"
return="java.lang.String"
abstract="false"
@@ -70221,8 +70576,21 @@
<parameter name="path" type="java.lang.String">
</parameter>
</method>
+<method name="getOriginalMimeType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
<method name="loadPlugIns"
- return="void"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -70246,7 +70614,7 @@
</parameter>
</method>
<method name="processDrmInfo"
- return="android.drm.DrmInfoStatus"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -70259,7 +70627,7 @@
</parameter>
</method>
<method name="removeAllRights"
- return="void"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -70270,7 +70638,7 @@
>
</method>
<method name="removeRights"
- return="void"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -70282,8 +70650,21 @@
<parameter name="path" type="java.lang.String">
</parameter>
</method>
+<method name="removeRights"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
<method name="saveRights"
- return="void"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -70301,11 +70682,37 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="setOnErrorListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorListener" type="android.drm.DrmManagerClient.OnErrorListener">
+</parameter>
+</method>
+<method name="setOnEventListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="eventListener" type="android.drm.DrmManagerClient.OnEventListener">
+</parameter>
+</method>
<method name="setOnInfoListener"
return="void"
abstract="false"
native="false"
- synchronized="false"
+ synchronized="true"
static="false"
final="false"
deprecated="not deprecated"
@@ -70315,7 +70722,7 @@
</parameter>
</method>
<method name="unloadPlugIns"
- return="void"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -70325,7 +70732,77 @@
visibility="public"
>
</method>
+<field name="ERROR_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
+<interface name="DrmManagerClient.OnErrorListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onError"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="client" type="android.drm.DrmManagerClient">
+</parameter>
+<parameter name="event" type="android.drm.DrmErrorEvent">
+</parameter>
+</method>
+</interface>
+<interface name="DrmManagerClient.OnEventListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onEvent"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="client" type="android.drm.DrmManagerClient">
+</parameter>
+<parameter name="event" type="android.drm.DrmEvent">
+</parameter>
+<parameter name="attributes" type="java.util.HashMap<java.lang.String, java.lang.Object>">
+</parameter>
+</method>
+</interface>
<interface name="DrmManagerClient.OnInfoListener"
abstract="true"
static="true"
@@ -90284,7 +90761,7 @@
type="float"
transient="false"
volatile="false"
- value="0.001f"
+ value="0.0010f"
static="true"
final="true"
deprecated="not deprecated"
@@ -236345,6 +236822,32 @@
<parameter name="listener" type="android.widget.SearchView.OnQueryChangeListener">
</parameter>
</method>
+<method name="setOnQueryTextFocusChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.view.View.OnFocusChangeListener">
+</parameter>
+</method>
+<method name="setOnSuggestionSelectionListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.widget.SearchView.OnSuggestionSelectionListener">
+</parameter>
+</method>
<method name="setQuery"
return="void"
abstract="false"
@@ -236479,6 +236982,40 @@
</parameter>
</method>
</interface>
+<interface name="SearchView.OnSuggestionSelectionListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onSuggestionClicked"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="onSuggestionSelected"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+</interface>
<interface name="SectionIndexer"
abstract="true"
static="false"
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 7decf9a..0159edd 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -171,9 +171,9 @@
runtime.start();
}
} else {
- LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
+ LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ee49d97..f08d88d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1745,35 +1745,11 @@
}
/**
- * @deprecated This functionality will be removed in the future; please do
- * not use.
- *
- * Control whether this activity is required to be persistent. By default
- * activities are not persistent; setting this to true will prevent the
- * system from stopping this activity or its process when running low on
- * resources.
- *
- * <p><em>You should avoid using this method</em>, it has severe negative
- * consequences on how well the system can manage its resources. A better
- * approach is to implement an application service that you control with
- * {@link Context#startService} and {@link Context#stopService}.
- *
- * @param isPersistent Control whether the current activity must be
- * persistent, true if so, false for the normal
- * behavior.
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}
+ * this is a no-op.
*/
@Deprecated
public void setPersistent(boolean isPersistent) {
- if (mParent == null) {
- try {
- ActivityManagerNative.getDefault()
- .setPersistent(mToken, isPersistent);
- } catch (RemoteException e) {
- // Empty
- }
- } else {
- throw new RuntimeException("setPersistent() not yet supported for embedded activities");
- }
}
/**
@@ -2876,6 +2852,10 @@
* <p>This can be useful if you know that you will never show a dialog again and
* want to avoid the overhead of saving and restoring it in the future.
*
+ * <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, this function
+ * will not throw an exception if you try to remove an ID that does not
+ * currently have an associated dialog.</p>
+ *
* @param id The id of the managed dialog.
*
* @see #onCreateDialog(int, Bundle)
@@ -2884,17 +2864,13 @@
* @see #dismissDialog(int)
*/
public final void removeDialog(int id) {
- if (mManagedDialogs == null) {
- return;
+ if (mManagedDialogs != null) {
+ final ManagedDialog md = mManagedDialogs.get(id);
+ if (md != null) {
+ md.mDialog.dismiss();
+ mManagedDialogs.remove(id);
+ }
}
-
- final ManagedDialog md = mManagedDialogs.get(id);
- if (md == null) {
- return;
- }
-
- md.mDialog.dismiss();
- mManagedDialogs.remove(id);
}
/**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b34c243..8cc6428 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -345,17 +345,6 @@
return true;
}
- case SET_PERSISTENT_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- boolean isPersistent = data.readInt() != 0;
- if (token != null) {
- setPersistent(token, isPersistent);
- }
- reply.writeNoException();
- return true;
- }
-
case ATTACH_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IApplicationThread app = ApplicationThreadNative.asInterface(
@@ -1640,18 +1629,6 @@
data.recycle();
reply.recycle();
}
- public void setPersistent(IBinder token, boolean isPersistent) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- data.writeInt(isPersistent ? 1 : 0);
- mRemote.transact(SET_PERSISTENT_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index f0477e5..0a40a98 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -22,9 +22,10 @@
import android.content.DialogInterface;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Bundle;
import android.os.Message;
+import android.util.Log;
+import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.View;
@@ -58,27 +59,29 @@
private AlertController mAlert;
protected AlertDialog(Context context) {
- this(context,
- context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB
- ? com.android.internal.R.style.Theme_Holo_Dialog_Alert
- : com.android.internal.R.style.Theme_Dialog_Alert);
+ this(context, getDefaultDialogTheme(context));
}
protected AlertDialog(Context context, int theme) {
- super(context, theme);
+ super(context, theme == 0 ? getDefaultDialogTheme(context) : theme);
mAlert = new AlertController(context, this, getWindow());
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
- super(context,
- context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB
- ? com.android.internal.R.style.Theme_Holo_Dialog_Alert
- : com.android.internal.R.style.Theme_Dialog_Alert);
+ super(context, getDefaultDialogTheme(context));
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
}
+ private static int getDefaultDialogTheme(Context context) {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
+ outValue, true);
+ Log.d("AlertDialog", "getDefaultDialogTheme data " + outValue.data + " id " + outValue.resourceId);
+ return outValue.resourceId;
+ }
+
/**
* Gets one of the buttons used in the dialog.
* <p>
@@ -280,10 +283,7 @@
* Constructor using a context for this builder and the {@link AlertDialog} it creates.
*/
public Builder(Context context) {
- this(context,
- context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB
- ? com.android.internal.R.style.Theme_Holo_Dialog_Alert
- : com.android.internal.R.style.Theme_Dialog_Alert);
+ this(context, getDefaultDialogTheme(context));
}
/**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 918ecf1..092fa2a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2788,7 +2788,7 @@
synchronized (this) {
if (mDiskWritesInFlight > 0) {
// If we know we caused it, it's not unexpected.
- Log.d(TAG, "disk write in flight, not unexpected.");
+ if (DEBUG) Log.d(TAG, "disk write in flight, not unexpected.");
return false;
}
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index a178c04..526129a 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -29,6 +29,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@@ -140,11 +141,14 @@
* <var>context</var>. If 0, the default dialog theme will be used.
*/
public Dialog(Context context, int theme) {
- mContext = new ContextThemeWrapper(
- context, theme == 0 ?
- (context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB
- ? com.android.internal.R.style.Theme_Holo_Dialog
- : com.android.internal.R.style.Theme_Dialog) : theme);
+ if (theme == 0) {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
+ outValue, true);
+ theme = outValue.resourceId;
+ }
+
+ mContext = new ContextThemeWrapper(context, theme);
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 013032c..f0a8dfd 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -99,6 +99,11 @@
public final static String COLUMN_LOCAL_URI = "local_uri";
/**
+ * The pathname of the file where the download is stored.
+ */
+ public final static String COLUMN_LOCAL_FILENAME = "local_filename";
+
+ /**
* Current status of the download, as one of the STATUS_* constants.
*/
public final static String COLUMN_STATUS = "status";
@@ -272,7 +277,8 @@
COLUMN_STATUS,
COLUMN_REASON,
COLUMN_BYTES_DOWNLOADED_SO_FAR,
- COLUMN_LAST_MODIFIED_TIMESTAMP
+ COLUMN_LAST_MODIFIED_TIMESTAMP,
+ COLUMN_LOCAL_FILENAME
};
// columns to request from DownloadProvider
@@ -915,6 +921,9 @@
if (column.equals(COLUMN_MEDIA_TYPE)) {
return getUnderlyingString(Downloads.COLUMN_MIME_TYPE);
}
+ if (column.equals(COLUMN_LOCAL_FILENAME)) {
+ return getUnderlyingString(Downloads.Impl._DATA);
+ }
assert column.equals(COLUMN_LOCAL_URI);
return getLocalUri();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index cd229e3..c9d5448 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -116,7 +116,6 @@
public void unbroadcastIntent(IApplicationThread caller, Intent intent) throws RemoteException;
/* oneway */
public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException;
- public void setPersistent(IBinder token, boolean isPersistent) throws RemoteException;
public void attachApplication(IApplicationThread app) throws RemoteException;
/* oneway */
public void activityIdle(IBinder token, Configuration config) throws RemoteException;
@@ -455,7 +454,7 @@
int REPORT_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
int GET_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
- int SET_PERSISTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
+
int FINISH_SUB_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
int GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
int START_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 3289120..da1aac4 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1319,12 +1319,36 @@
}
/**
- * If a sync is active returns the information about it, otherwise returns false.
+ * If a sync is active returns the information about it, otherwise returns null.
+ * <p>
* @return the SyncInfo for the currently active sync or null if one is not active.
+ * @deprecated
+ * Since multiple concurrent syncs are now supported you should use
+ * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
+ * This method returns the first item from the list of current syncs
+ * or null if there are none.
*/
+ @Deprecated
public static SyncInfo getCurrentSync() {
try {
- return getContentService().getCurrentSync();
+ final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
+ if (syncs.isEmpty()) {
+ return null;
+ }
+ return syncs.get(0);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Returns a list with information about all the active syncs. This list will be empty
+ * if there are no active syncs.
+ * @return a List of SyncInfo objects for the currently active syncs.
+ */
+ public static List<SyncInfo> getCurrentSyncs() {
+ try {
+ return getContentService().getCurrentSyncs();
} catch (RemoteException e) {
throw new RuntimeException("the ContentService should always be reachable", e);
}
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index fc2dfc0..afe8483 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -386,19 +386,15 @@
return false;
}
- public SyncInfo getCurrentSync() {
+ public List<SyncInfo> getCurrentSyncs() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getCurrentSync();
- }
+ return getSyncManager().getSyncStorageEngine().getCurrentSyncs();
} finally {
restoreCallingIdentity(identityToken);
}
- return null;
}
public SyncStatusInfo getSyncStatus(Account account, String authority) {
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index a6368d5..86a9392 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -104,7 +104,7 @@
*/
boolean isSyncActive(in Account account, String authority);
- SyncInfo getCurrentSync();
+ List<SyncInfo> getCurrentSyncs();
/**
* Returns the types of the SyncAdapters that are registered with the system.
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index 616b05f..abfe964 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -18,12 +18,13 @@
import android.accounts.Account;
import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Parcelable.Creator;
/**
* Information about the sync operation that is currently underway.
*/
-public class SyncInfo {
+public class SyncInfo implements Parcelable {
/** @hide */
public final int authorityId;
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 487f6ce..0639573 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -95,7 +95,7 @@
public static final long NOT_IN_BACKOFF_MODE = -1;
- private static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT =
+ public static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT =
new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
// TODO: i18n -- grab these out of resources.
@@ -1088,23 +1088,6 @@
}
/**
- * Return the currently active sync information, or null if there is no
- * active sync. Note that the returned object is the real, live active
- * sync object, so be careful what you do with it.
- * <p>
- * Since multiple concurrent syncs are now supported you should use
- * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
- * This method returns the first item from the list of current syncs
- * or null if there are none.
- * @deprecated use {@link #getCurrentSyncs()}
- */
- public SyncInfo getCurrentSync() {
- synchronized (mAuthorities) {
- return !mCurrentSyncs.isEmpty() ? mCurrentSyncs.get(0) : null;
- }
- }
-
- /**
* Return a list of the currently active syncs. Note that the returned items are the
* real, live active sync objects, so be careful what you do with it.
*/
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 89e8ab7..aba37a4 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -416,8 +416,10 @@
// BEGIN STOPSHIP remove the following line
t = new RequeryOnUiThreadException(packageName);
// END STOPSHIP
- Log.w(TAG, "should not attempt requery on main (UI) thread: app = " +
- packageName == null ? "'unknown'" : packageName, t);
+ String s = packageName == null ? "'unknown'" : packageName;
+ Log.w(TAG, "should not attempt requery on main (UI) thread: app = " + s +
+ " (database: " + mQuery.mDatabase.getPath() +
+ ", query: " + mQuery.mSql + ")", t);
}
}
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index a98a305..0e921e9 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -2114,7 +2114,14 @@
return;
}
- if (!mCacheFullWarning && mCompiledQueries.size() == mMaxSqlCacheSize) {
+ int maxCacheSz = (mConnectionNum == 0) ? mMaxSqlCacheSize :
+ mParentConnObj.mMaxSqlCacheSize;
+ boolean printWarning =
+ (mConnectionNum == 0)
+ ? (!mCacheFullWarning && mCompiledQueries.size() == maxCacheSz)
+ : (!mParentConnObj.mCacheFullWarning &&
+ mParentConnObj.mCompiledQueries.size() == maxCacheSz);
+ if (printWarning) {
/*
* cache size of {@link #mMaxSqlCacheSize} is not enough for this app.
* log a warning.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 7b930d5..a27ba84 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1354,8 +1354,23 @@
/**
* Sets the dimensions for preview pictures.
*
+ * The sides of width and height are based on camera orientation. That
+ * is, the preview size is the size before it is rotated by display
+ * orientation. So applications need to consider the display orientation
+ * while setting preview size. For example, suppose the camera supports
+ * both 480x320 and 320x480 preview sizes. The application wants a 3:2
+ * preview ratio. If the display orientation is set to 0 or 180, preview
+ * size should be set to 480x320. If the display orientation is set to
+ * 90 or 270, preview size should be set to 320x480. The display
+ * orientation should also be considered while setting picture size and
+ * thumbnail size.
+ *
* @param width the width of the pictures, in pixels
* @param height the height of the pictures, in pixels
+ * @see #setDisplayOrientation(int)
+ * @see #getCameraInfo(int, CameraInfo)
+ * @see #setPictureSize(int, int)
+ * @see #setJpegThumbnailSize(int, int)
*/
public void setPreviewSize(int width, int height) {
String v = Integer.toString(width) + "x" + Integer.toString(height);
@@ -1389,8 +1404,12 @@
* applications set both width and height to 0, EXIF will not contain
* thumbnail.
*
+ * Applications need to consider the display orientation. See {@link
+ * #setPreviewSize(int,int)} for reference.
+ *
* @param width the width of the thumbnail, in pixels
* @param height the height of the thumbnail, in pixels
+ * @see #setPreviewSize(int,int)
*/
public void setJpegThumbnailSize(int width, int height) {
set(KEY_JPEG_THUMBNAIL_WIDTH, width);
@@ -1606,8 +1625,13 @@
/**
* Sets the dimensions for pictures.
*
+ * Applications need to consider the display orientation. See {@link
+ * #setPreviewSize(int,int)} for reference.
+ *
* @param width the width for pictures, in pixels
* @param height the height for pictures, in pixels
+ * @see #setPreviewSize(int,int)
+ *
*/
public void setPictureSize(int width, int height) {
String v = Integer.toString(width) + "x" + Integer.toString(height);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index cb302da..3f03a2a 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -34,26 +34,26 @@
private final InetAddress address;
/**
- * Network prefix
+ * Network prefix length
*/
- private final int prefix;
+ private final int prefixLength;
public LinkAddress(InetAddress address, InetAddress mask) {
this.address = address;
- this.prefix = computeprefix(mask);
+ this.prefixLength = computeprefixLength(mask);
}
- public LinkAddress(InetAddress address, int prefix) {
+ public LinkAddress(InetAddress address, int prefixLength) {
this.address = address;
- this.prefix = prefix;
+ this.prefixLength = prefixLength;
}
public LinkAddress(InterfaceAddress interfaceAddress) {
this.address = interfaceAddress.getAddress();
- this.prefix = interfaceAddress.getNetworkPrefixLength();
+ this.prefixLength = interfaceAddress.getNetworkPrefixLength();
}
- private static int computeprefix(InetAddress mask) {
+ private static int computeprefixLength(InetAddress mask) {
int count = 0;
for (byte b : mask.getAddress()) {
for (int i = 0; i < 8; ++i) {
@@ -67,12 +67,12 @@
@Override
public String toString() {
- return (address == null ? "" : (address.getHostAddress() + "/" + prefix));
+ return (address == null ? "" : (address.getHostAddress() + "/" + prefixLength));
}
/**
* Compares this {@code LinkAddress} instance against the specified address
- * in {@code obj}. Two addresses are equal if their InetAddress and prefix
+ * in {@code obj}. Two addresses are equal if their InetAddress and prefixLength
* are equal
*
* @param obj the object to be tested for equality.
@@ -85,7 +85,7 @@
}
LinkAddress linkAddress = (LinkAddress) obj;
return this.address.equals(linkAddress.address) &&
- this.prefix == linkAddress.prefix;
+ this.prefixLength == linkAddress.prefixLength;
}
/**
@@ -98,8 +98,8 @@
/**
* Get network prefix length
*/
- public int getNetworkPrefix() {
- return prefix;
+ public int getNetworkPrefixLength() {
+ return prefixLength;
}
/**
@@ -118,7 +118,7 @@
if (address != null) {
dest.writeByte((byte)1);
dest.writeByteArray(address.getAddress());
- dest.writeInt(prefix);
+ dest.writeInt(prefixLength);
} else {
dest.writeByte((byte)0);
}
@@ -132,14 +132,14 @@
new Creator<LinkAddress>() {
public LinkAddress createFromParcel(Parcel in) {
InetAddress address = null;
- int prefix = 0;
+ int prefixLength = 0;
if (in.readByte() == 1) {
try {
address = InetAddress.getByAddress(in.createByteArray());
- prefix = in.readInt();
+ prefixLength = in.readInt();
} catch (UnknownHostException e) { }
}
- return new LinkAddress(address, prefix);
+ return new LinkAddress(address, prefixLength);
}
public LinkAddress[] newArray(int size) {
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 01004c2..6b1fe99 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -146,6 +146,57 @@
}
/**
+ * Convert a IPv4 address from an InetAddress to an integer
+ * @param inetAddr is an InetAddress corresponding to the IPv4 address
+ * @return the IP address as an integer in network byte order
+ */
+ public static int inetAddressToInt(InetAddress inetAddr)
+ throws IllegalArgumentException {
+ byte [] addr = inetAddr.getAddress();
+ if (addr.length != 4) {
+ throw new IllegalArgumentException("Not an IPv4 address");
+ }
+ return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
+ ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
+ }
+
+ /**
+ * Convert a network prefix length to an IPv4 netmask integer
+ * @param prefixLength
+ * @return the IPv4 netmask as an integer in network byte order
+ */
+ public static int prefixLengthToNetmaskInt(int prefixLength)
+ throws IllegalArgumentException {
+ if (prefixLength < 0 || prefixLength > 32) {
+ throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
+ }
+ int value = 0xffffffff << (32 - prefixLength);
+ return Integer.reverseBytes(value);
+ }
+
+ public static boolean isIpAddress(String address) {
+ //TODO: Add NetworkUtils support for IPv6 configuration and
+ //remove IPv4 validation and use a generic InetAddress validation
+ try {
+ String[] parts = address.split("\\.");
+ if (parts.length != 4) {
+ return false;
+ }
+ int a = Integer.parseInt(parts[0]);
+ if (a < 0 || a > 255) return false;
+ a = Integer.parseInt(parts[1]);
+ if (a < 0 || a > 255) return false;
+ a = Integer.parseInt(parts[2]);
+ if (a < 0 || a > 255) return false;
+ a = Integer.parseInt(parts[3]);
+ if (a < 0 || a > 255) return false;
+ } catch (NumberFormatException ex) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Add a default route through the specified gateway.
* @param interfaceName interface on which the route should be added
* @param gw the IP address of the gateway to which the route is desired,
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 23fdb0b..fa23458 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -152,7 +152,7 @@
/** @return time when the entry was originally created. */
public long getTimeMillis() { return mTimeMillis; }
- /** @return flags describing the content returned by @{link #getInputStream()}. */
+ /** @return flags describing the content returned by {@link #getInputStream()}. */
public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses.
/**
@@ -288,8 +288,8 @@
}
/**
- * Gets the next entry from the drop box *after* the specified time.
- * Requires android.permission.READ_LOGS. You must always call
+ * Gets the next entry from the drop box <em>after</em> the specified time.
+ * Requires <code>android.permission.READ_LOGS</code>. You must always call
* {@link Entry#close()} on the return value!
*
* @param tag of entry to look for, null for all tags
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index be5b685..bb07825 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -34,16 +34,19 @@
Message mMessages;
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
- private boolean mQuiting = false;
+ private boolean mQuiting;
boolean mQuitAllowed = true;
+ // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
+ private boolean mBlocked;
+
@SuppressWarnings("unused")
private int mPtr; // used by native code
private native void nativeInit();
private native void nativeDestroy();
- private native boolean nativePollOnce(int timeoutMillis);
- private native void nativeWake();
+ private native void nativePollOnce(int ptr, int timeoutMillis);
+ private native void nativeWake(int ptr);
/**
* Callback interface for discovering when a thread is going to block
@@ -113,7 +116,7 @@
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
- nativePollOnce(nextPollTimeoutMillis);
+ nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
@@ -122,7 +125,9 @@
if (msg != null) {
final long when = msg.when;
if (now >= when) {
+ mBlocked = false;
mMessages = msg.next;
+ msg.next = null;
if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
@@ -139,6 +144,7 @@
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
+ mBlocked = true;
continue;
}
@@ -185,6 +191,7 @@
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
+ final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
@@ -201,6 +208,7 @@
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
+ needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
@@ -209,9 +217,12 @@
}
msg.next = prev.next;
prev.next = msg;
+ needWake = false; // still waiting on head, no need to wake up
}
}
- nativeWake();
+ if (needWake) {
+ nativeWake(mPtr);
+ }
return true;
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b87dbc5..3de7962 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -215,6 +215,49 @@
}
/**
+ * Return a string for the EGL error code, or the hex representation
+ * if an unknown error.
+ * @param error EGL error.
+ * @return Error string.
+ */
+ static String getEGLErrorString(int error) {
+ switch (error) {
+ case EGL10.EGL_SUCCESS:
+ return "EGL_SUCCESS";
+ case EGL10.EGL_NOT_INITIALIZED:
+ return "EGL_NOT_INITIALIZED";
+ case EGL10.EGL_BAD_ACCESS:
+ return "EGL_BAD_ACCESS";
+ case EGL10.EGL_BAD_ALLOC:
+ return "EGL_BAD_ALLOC";
+ case EGL10.EGL_BAD_ATTRIBUTE:
+ return "EGL_BAD_ATTRIBUTE";
+ case EGL10.EGL_BAD_CONFIG:
+ return "EGL_BAD_CONFIG";
+ case EGL10.EGL_BAD_CONTEXT:
+ return "EGL_BAD_CONTEXT";
+ case EGL10.EGL_BAD_CURRENT_SURFACE:
+ return "EGL_BAD_CURRENT_SURFACE";
+ case EGL10.EGL_BAD_DISPLAY:
+ return "EGL_BAD_DISPLAY";
+ case EGL10.EGL_BAD_MATCH:
+ return "EGL_BAD_MATCH";
+ case EGL10.EGL_BAD_NATIVE_PIXMAP:
+ return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL10.EGL_BAD_NATIVE_WINDOW:
+ return "EGL_BAD_NATIVE_WINDOW";
+ case EGL10.EGL_BAD_PARAMETER:
+ return "EGL_BAD_PARAMETER";
+ case EGL10.EGL_BAD_SURFACE:
+ return "EGL_BAD_SURFACE";
+ case EGL11.EGL_CONTEXT_LOST:
+ return "EGL_CONTEXT_LOST";
+ default:
+ return "0x" + Integer.toHexString(error);
+ }
+ }
+
+ /**
* Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
* is invoked and the requested flag is turned off. The error code is
* also logged as a warning.
@@ -230,7 +273,7 @@
// we'll try again if it was context lost
setRequested(false);
}
- Log.w(LOG_TAG, "EGL error: " + Integer.toHexString(error));
+ Log.w(LOG_TAG, "EGL error: " + getEGLErrorString(error));
}
}
}
@@ -276,13 +319,15 @@
sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (sEglDisplay == EGL10.EGL_NO_DISPLAY) {
- throw new RuntimeException("eglGetDisplay failed");
+ throw new RuntimeException("eglGetDisplay failed "
+ + getEGLErrorString(sEgl.eglGetError()));
}
// We can now initialize EGL for that display
int[] version = new int[2];
if (!sEgl.eglInitialize(sEglDisplay, version)) {
- throw new RuntimeException("eglInitialize failed");
+ throw new RuntimeException("eglInitialize failed "
+ + getEGLErrorString(sEgl.eglGetError()));
}
sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
@@ -332,7 +377,8 @@
Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
return null;
}
- throw new RuntimeException("createWindowSurface failed");
+ throw new RuntimeException("createWindowSurface failed "
+ + getEGLErrorString(error));
}
/*
@@ -340,7 +386,8 @@
* the context is current and bound to a surface.
*/
if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
- throw new RuntimeException("eglMakeCurrent failed");
+ throw new RuntimeException("eglMakeCurrent failed "
+ + getEGLErrorString(sEgl.eglGetError()));
}
return sEglContext.getGL();
@@ -454,7 +501,8 @@
if (sEgl.eglGetCurrentContext() != sEglContext ||
sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
- throw new RuntimeException("eglMakeCurrent failed");
+ throw new RuntimeException("eglMakeCurrent failed "
+ + getEGLErrorString(sEgl.eglGetError()));
}
}
}
@@ -471,7 +519,8 @@
EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
int[] index = new int[1];
if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) {
- throw new IllegalArgumentException("eglChooseConfig failed");
+ throw new IllegalArgumentException("eglChooseConfig failed "
+ + getEGLErrorString(egl.eglGetError()));
}
int numConfigs = index[0];
@@ -481,7 +530,8 @@
EGLConfig[] configs = new EGLConfig[numConfigs];
if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) {
- throw new IllegalArgumentException("eglChooseConfig failed");
+ throw new IllegalArgumentException("eglChooseConfig failed "
+ + getEGLErrorString(egl.eglGetError()));
}
EGLConfig config = chooseConfig(egl, display, configs);
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index 43c957a..9e800df 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -28,8 +28,21 @@
private static final boolean DEBUG = false;
+ /**
+ * Interface to receive notification of when an InputQueue is associated
+ * and dissociated with a thread.
+ */
public static interface Callback {
+ /**
+ * Called when the given InputQueue is now associated with the
+ * thread making this call, so it can start receiving events from it.
+ */
void onInputQueueCreated(InputQueue queue);
+
+ /**
+ * Called when the given InputQueue is no longer associated with
+ * the thread and thus not dispatching events.
+ */
void onInputQueueDestroyed(InputQueue queue);
}
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 3e2e92b..2a76e33 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -109,7 +109,9 @@
}
public void setAllow180Rotation(boolean allowed) {
- mSensorEventListener.setAllow180Rotation(allowed);
+ if (mSensorEventListener != null) {
+ mSensorEventListener.setAllow180Rotation(allowed);
+ }
}
public int getCurrentRotation(int lastRotation) {
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index b00f88c..8c9f266 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -710,6 +710,9 @@
break;
case ADD_MESSAGE_TO_CONSOLE:
+ if (mWebChromeClient == null) {
+ break;
+ }
String message = msg.getData().getString("message");
String sourceID = msg.getData().getString("sourceID");
int lineNumber = msg.getData().getInt("lineNumber");
@@ -786,7 +789,9 @@
host, realm, username, password);
break;
case SET_INSTALLABLE_WEBAPP:
- mWebChromeClient.setInstallableWebApp();
+ if (mWebChromeClient != null) {
+ mWebChromeClient.setInstallableWebApp();
+ }
break;
}
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index d6c2db1..e2a6f7b 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -111,6 +111,7 @@
private Drawable mBelowAnchorBackgroundDrawable;
private boolean mAboveAnchor;
+ private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
private OnDismissListener mOnDismissListener;
private boolean mIgnoreCheekPress = false;
@@ -634,6 +635,25 @@
}
/**
+ * Set the layout type for this window. Should be one of the TYPE constants defined in
+ * {@link WindowManager.LayoutParams}.
+ *
+ * @param layoutType Layout type for this window.
+ * @hide
+ */
+ public void setWindowLayoutType(int layoutType) {
+ mWindowLayoutType = layoutType;
+ }
+
+ /**
+ * @return The layout type for this window.
+ * @hide
+ */
+ public int getWindowLayoutType() {
+ return mWindowLayoutType;
+ }
+
+ /**
* <p>Change the width and height measure specs that are given to the
* window manager by the popup. By default these are 0, meaning that
* the current width or height is requested as an explicit size from
@@ -922,7 +942,7 @@
p.format = PixelFormat.TRANSLUCENT;
}
p.flags = computeFlags(p.flags);
- p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+ p.type = mWindowLayoutType;
p.token = token;
p.softInputMode = mSoftInputMode;
p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index dd67197..cfd6754 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -56,6 +56,8 @@
private OnQueryChangeListener mOnQueryChangeListener;
private OnCloseListener mOnCloseListener;
+ private OnFocusChangeListener mOnQueryTextFocusChangeListener;
+ private OnSuggestionSelectionListener mOnSuggestionListener;
private boolean mIconifiedByDefault;
private boolean mIconified;
@@ -68,6 +70,7 @@
private boolean mSubmitButtonEnabled;
private CharSequence mQueryHint;
private boolean mQueryRefinement;
+ private boolean mClearingFocus;
private SearchableInfo mSearchable;
@@ -117,6 +120,32 @@
boolean onClose();
}
+ /**
+ * Callback interface for selection events on suggestions. These callbacks
+ * are only relevant when a SearchableInfo has been specified by {@link #setSearchableInfo}.
+ */
+ public interface OnSuggestionSelectionListener {
+
+ /**
+ * Called when a suggestion was selected by navigating to it.
+ * @param position the absolute position in the list of suggestions.
+ *
+ * @return true if the listener handles the event and wants to override the default
+ * behavior of possibly rewriting the query based on the selected item, false otherwise.
+ */
+ boolean onSuggestionSelected(int position);
+
+ /**
+ * Called when a suggestion was clicked.
+ * @param position the absolute position of the clicked item in the list of suggestions.
+ *
+ * @return true if the listener handles the event and wants to override the default
+ * behavior of launching any intent or submitting a search query specified on that item.
+ * Return false otherwise.
+ */
+ boolean onSuggestionClicked(int position);
+ }
+
public SearchView(Context context) {
this(context, null);
}
@@ -141,6 +170,15 @@
mQueryTextView.setOnEditorActionListener(mOnEditorActionListener);
mQueryTextView.setOnItemClickListener(mOnItemClickListener);
mQueryTextView.setOnItemSelectedListener(mOnItemSelectedListener);
+ // Inform any listener of focus changes
+ mQueryTextView.setOnFocusChangeListener(new OnFocusChangeListener() {
+
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (mOnQueryTextFocusChangeListener != null) {
+ mOnQueryTextFocusChangeListener.onFocusChange(SearchView.this, hasFocus);
+ }
+ }
+ });
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SearchView, 0, 0);
setIconifiedByDefault(a.getBoolean(R.styleable.SearchView_iconifiedByDefault, true));
@@ -165,6 +203,27 @@
updateViewsVisibility(mIconifiedByDefault);
}
+ /** @hide */
+ @Override
+ public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
+ if (mClearingFocus) return false;
+ boolean result = mQueryTextView.requestFocus(direction, previouslyFocusedRect);
+ if (result && !isIconified()) {
+ setImeVisibility(true);
+ }
+ return result;
+ }
+
+ /** @hide */
+ @Override
+ public void clearFocus() {
+ mClearingFocus = true;
+ super.clearFocus();
+ mQueryTextView.clearFocus();
+ setImeVisibility(false);
+ mClearingFocus = false;
+ }
+
/**
* Sets a listener for user actions within the SearchView.
*
@@ -185,6 +244,24 @@
}
/**
+ * Sets a listener to inform when the focus of the query text field changes.
+ *
+ * @param listener the listener to inform of focus changes.
+ */
+ public void setOnQueryTextFocusChangeListener(OnFocusChangeListener listener) {
+ mOnQueryTextFocusChangeListener = listener;
+ }
+
+ /**
+ * Sets a listener to inform when a suggestion is focused or clicked.
+ *
+ * @param listener the listener to inform of suggestion selection events.
+ */
+ public void setOnSuggestionSelectionListener(OnSuggestionSelectionListener listener) {
+ mOnSuggestionListener = listener;
+ }
+
+ /**
* Sets a query string in the text field and optionally submits the query as well.
*
* @param query the query string. This replaces any query text already present in the
@@ -224,6 +301,7 @@
public void setIconifiedByDefault(boolean iconified) {
mIconifiedByDefault = iconified;
updateViewsVisibility(iconified);
+ setImeVisibility(!iconified);
}
/**
@@ -340,28 +418,25 @@
final int visCollapsed = collapsed ? VISIBLE : GONE;
// Visibility of views that are visible when expanded
final int visExpanded = collapsed ? GONE : VISIBLE;
+ // Is there text in the query
+ final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText());
mSearchButton.setVisibility(visCollapsed);
- mSubmitButton.setVisibility(mSubmitButtonEnabled ? visExpanded : GONE);
+ mSubmitButton.setVisibility(mSubmitButtonEnabled && hasText ? visExpanded : GONE);
mSearchEditFrame.setVisibility(visExpanded);
-
- setImeVisibility(!collapsed);
}
private void setImeVisibility(boolean visible) {
- // don't mess with the soft input if we're not iconified by default
- if (mIconifiedByDefault) {
- InputMethodManager imm = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ InputMethodManager imm = (InputMethodManager)
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- // We made sure the IME was displayed, so also make sure it is closed
- // when we go away.
- if (imm != null) {
- if (visible) {
- imm.showSoftInputUnchecked(0, null);
- } else {
- imm.hideSoftInputFromWindow(getWindowToken(), 0);
- }
+ // We made sure the IME was displayed, so also make sure it is closed
+ // when we go away.
+ if (imm != null) {
+ if (visible) {
+ imm.showSoftInputUnchecked(0, null);
+ } else {
+ imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
}
}
@@ -478,6 +553,7 @@
|| !mOnQueryChangeListener.onSubmitQuery(query.toString())) {
if (mSearchable != null) {
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
+ setImeVisibility(false);
}
}
}
@@ -485,7 +561,14 @@
private void onCloseClicked() {
if (mOnCloseListener == null || !mOnCloseListener.onClose()) {
- mQueryTextView.setText("");
+ CharSequence text = mQueryTextView.getText();
+ if (TextUtils.isEmpty(text)) {
+ // query field already empty, hide the keyboard and remove focus
+ mQueryTextView.clearFocus();
+ setImeVisibility(false);
+ } else {
+ mQueryTextView.setText("");
+ }
updateViewsVisibility(mIconifiedByDefault);
}
}
@@ -493,6 +576,7 @@
private void onSearchClicked() {
mQueryTextView.requestFocus();
updateViewsVisibility(false);
+ setImeVisibility(true);
}
private final OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
@@ -503,7 +587,10 @@
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (DBG)
Log.d(LOG_TAG, "onItemClick() position " + position);
- launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
+ if (mOnSuggestionListener == null
+ || !mOnSuggestionListener.onSuggestionClicked(position)) {
+ launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
+ }
}
};
@@ -517,7 +604,10 @@
Log.d(LOG_TAG, "onItemSelected() position " + position);
// A suggestion has been selected, rewrite the query if possible,
// otherwise the restore the original query.
- rewriteQueryFromSuggestion(position);
+ if (mOnSuggestionListener == null
+ || !mOnSuggestionListener.onSuggestionSelected(position)) {
+ rewriteQueryFromSuggestion(position);
+ }
}
/**
@@ -722,13 +812,4 @@
public void afterTextChanged(Editable s) {
}
};
-
- /*
- * Avoid getting focus when searching for something to focus on.
- * The user will have to touch the text view to get focus.
- */
- protected boolean onRequestFocusInDescendants(int direction,
- Rect previouslyFocusedRect) {
- return false;
- }
- }
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d63af4e..6b19ecf 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -96,6 +96,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
+import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
import android.view.ViewRoot;
@@ -293,9 +294,13 @@
}
InputMethodState mInputMethodState;
- private int mTextSelectHandleLeftRes;
- private int mTextSelectHandleRightRes;
- private int mTextSelectHandleRes;
+ int mTextSelectHandleLeftRes;
+ int mTextSelectHandleRightRes;
+ int mTextSelectHandleRes;
+
+ Drawable mSelectHandleLeft;
+ Drawable mSelectHandleRight;
+ Drawable mSelectHandleCenter;
/*
* Kick-start the font cache for the zygote process (to pay the cost of
@@ -4364,6 +4369,7 @@
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
+ mEnterKeyIsDown = true;
// If ALT modifier is held, then we always insert a
// newline character.
if ((event.getMetaState()&KeyEvent.META_ALT_ON) == 0) {
@@ -4396,6 +4402,7 @@
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
+ mDPadCenterIsDown = true;
if (shouldAdvanceFocusOnEnter()) {
return 0;
}
@@ -4490,6 +4497,7 @@
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
+ mDPadCenterIsDown = false;
/*
* If there is a click listener, just call through to
* super, which will invoke it.
@@ -4510,6 +4518,7 @@
return super.onKeyUp(keyCode, event);
case KeyEvent.KEYCODE_ENTER:
+ mEnterKeyIsDown = false;
if (mInputContentType != null
&& mInputContentType.onEditorActionListener != null
&& mInputContentType.enterDown) {
@@ -7288,9 +7297,21 @@
}
// Two ints packed in a long
+ return packRangeInLong(start, end);
+ }
+
+ private static long packRangeInLong(int start, int end) {
return (((long) start) << 32) | end;
}
+ private static int extractRangeStartFromLong(long range) {
+ return (int) (range >>> 32);
+ }
+
+ private static int extractRangeEndFromLong(long range) {
+ return (int) (range & 0x00000000FFFFFFFFL);
+ }
+
private void selectCurrentWord() {
// In case selection mode is started after an orientation change or after a select all,
// use the current selection instead of creating one
@@ -7298,67 +7319,31 @@
return;
}
- int selectionStart, selectionEnd;
+ int minOffset, maxOffset;
- // selectionModifierCursorController is not null at that point
- SelectionModifierCursorController selectionModifierCursorController =
- ((SelectionModifierCursorController) mSelectionModifierCursorController);
- int minOffset = selectionModifierCursorController.getMinTouchOffset();
- int maxOffset = selectionModifierCursorController.getMaxTouchOffset();
-
- if (minOffset == maxOffset) {
- int offset = Math.max(0, Math.min(minOffset, mTransformed.length()));
-
- // Tolerance, number of charaters around tapped position
- final int range = 1;
- final int max = mTransformed.length() - 1;
-
- // 'Smart' word selection: detect position between words
- for (int i = -range; i <= range; i++) {
- int index = offset + i;
- if (index >= 0 && index <= max) {
- if (Character.isSpaceChar(mTransformed.charAt(index))) {
- // Select current space
- selectionStart = index;
- selectionEnd = selectionStart + 1;
-
- // Extend selection to maximum space range
- while (selectionStart > 0 &&
- Character.isSpaceChar(mTransformed.charAt(selectionStart - 1))) {
- selectionStart--;
- }
- while (selectionEnd < max &&
- Character.isSpaceChar(mTransformed.charAt(selectionEnd))) {
- selectionEnd++;
- }
-
- Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
- return;
- }
- }
- }
-
- // 'Smart' word selection: detect position at beginning or end of text.
- if (offset <= range) {
- Selection.setSelection((Spannable) mText, 0, 0);
- return;
- }
- if (offset >= (max - range)) {
- Selection.setSelection((Spannable) mText, max + 1, max + 1);
- return;
- }
+ if (mDPadCenterIsDown || mEnterKeyIsDown) {
+ minOffset = getSelectionStart();
+ maxOffset = getSelectionEnd();
+ } else {
+ // selectionModifierCursorController is not null at that point
+ SelectionModifierCursorController selectionModifierCursorController =
+ ((SelectionModifierCursorController) mSelectionModifierCursorController);
+ minOffset = selectionModifierCursorController.getMinTouchOffset();
+ maxOffset = selectionModifierCursorController.getMaxTouchOffset();
}
+ int selectionStart, selectionEnd;
+
long wordLimits = getWordLimitsAt(minOffset);
if (wordLimits >= 0) {
- selectionStart = (int) (wordLimits >>> 32);
+ selectionStart = extractRangeStartFromLong(wordLimits);
} else {
selectionStart = Math.max(minOffset - 5, 0);
}
wordLimits = getWordLimitsAt(maxOffset);
if (wordLimits >= 0) {
- selectionEnd = (int) (wordLimits & 0x00000000FFFFFFFFL);
+ selectionEnd = extractRangeEndFromLong(wordLimits);
} else {
selectionEnd = Math.min(maxOffset + 5, mText.length());
}
@@ -7487,7 +7472,6 @@
switch (id) {
case ID_COPY_URL:
-
URLSpan[] urls = ((Spanned) mText).getSpans(min, max, URLSpan.class);
if (urls.length >= 1) {
ClipData clip = null;
@@ -7513,6 +7497,49 @@
return false;
}
+ /**
+ * Prepare text so that there are not zero or two spaces at beginning and end of region defined
+ * by [min, max] when replacing this region by paste.
+ */
+ private long prepareSpacesAroundPaste(int min, int max, CharSequence paste) {
+ // Paste adds/removes spaces before or after insertion as needed.
+ if (Character.isSpaceChar(paste.charAt(0))) {
+ if (min > 0 && Character.isSpaceChar(mTransformed.charAt(min - 1))) {
+ // Two spaces at beginning of paste: remove one
+ final int originalLength = mText.length();
+ ((Editable) mText).replace(min - 1, min, "");
+ // Due to filters, there is no garantee that exactly one character was
+ // removed. Count instead.
+ final int delta = mText.length() - originalLength;
+ min += delta;
+ max += delta;
+ }
+ } else {
+ if (min > 0 && !Character.isSpaceChar(mTransformed.charAt(min - 1))) {
+ // No space at beginning of paste: add one
+ final int originalLength = mText.length();
+ ((Editable) mText).replace(min, min, " ");
+ // Taking possible filters into account as above.
+ final int delta = mText.length() - originalLength;
+ min += delta;
+ max += delta;
+ }
+ }
+
+ if (Character.isSpaceChar(paste.charAt(paste.length() - 1))) {
+ if (max < mText.length() && Character.isSpaceChar(mTransformed.charAt(max))) {
+ // Two spaces at end of paste: remove one
+ ((Editable) mText).replace(max, max + 1, "");
+ }
+ } else {
+ if (max < mText.length() && !Character.isSpaceChar(mTransformed.charAt(max))) {
+ // No space at end of paste: add one
+ ((Editable) mText).replace(max, max, " ");
+ }
+ }
+ return packRangeInLong(min, max);
+ }
+
@Override
public boolean performLongClick() {
if (super.performLongClick()) {
@@ -7704,6 +7731,9 @@
CharSequence paste = clip.getItem(i).coerceToText(getContext());
if (paste != null) {
if (!didfirst) {
+ long minMax = prepareSpacesAroundPaste(min, max, paste);
+ min = extractRangeStartFromLong(minMax);
+ max = extractRangeEndFromLong(minMax);
Selection.setSelection((Spannable) mText, max);
((Editable) mText).replace(min, max, paste);
} else {
@@ -7714,7 +7744,6 @@
}
stopSelectionActionMode();
}
-
return true;
case ID_CUT:
@@ -7790,26 +7819,75 @@
private int mPositionY;
private CursorController mController;
private boolean mIsDragging;
- private float mOffsetX;
- private float mOffsetY;
+ private float mTouchToWindowOffsetX;
+ private float mTouchToWindowOffsetY;
private float mHotspotX;
private float mHotspotY;
+ private int mHeight;
+ private float mTouchOffsetY;
private int mLastParentX;
private int mLastParentY;
- public HandleView(CursorController controller, Drawable handle) {
+ public static final int LEFT = 0;
+ public static final int CENTER = 1;
+ public static final int RIGHT = 2;
+
+ public HandleView(CursorController controller, int pos) {
super(TextView.this.mContext);
mController = controller;
- mDrawable = handle;
mContainer = new PopupWindow(TextView.this.mContext, null,
com.android.internal.R.attr.textSelectHandleWindowStyle);
mContainer.setSplitTouchEnabled(true);
mContainer.setClippingEnabled(false);
+ mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
- final int handleWidth = mDrawable.getIntrinsicWidth();
+ setOrientation(pos);
+ }
+
+ public void setOrientation(int pos) {
+ int handleWidth;
+ switch (pos) {
+ case LEFT: {
+ if (mSelectHandleLeft == null) {
+ mSelectHandleLeft = mContext.getResources().getDrawable(
+ mTextSelectHandleLeftRes);
+ }
+ mDrawable = mSelectHandleLeft;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 4 * 3;
+ break;
+ }
+
+ case RIGHT: {
+ if (mSelectHandleRight == null) {
+ mSelectHandleRight = mContext.getResources().getDrawable(
+ mTextSelectHandleRightRes);
+ }
+ mDrawable = mSelectHandleRight;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 4;
+ break;
+ }
+
+ case CENTER:
+ default: {
+ if (mSelectHandleCenter == null) {
+ mSelectHandleCenter = mContext.getResources().getDrawable(
+ mTextSelectHandleRes);
+ }
+ mDrawable = mSelectHandleCenter;
+ handleWidth = mDrawable.getIntrinsicWidth();
+ mHotspotX = handleWidth / 2;
+ break;
+ }
+ }
+
final int handleHeight = mDrawable.getIntrinsicHeight();
- mHotspotX = handleWidth * 0.5f;
- mHotspotY = -handleHeight * 0.2f;
+
+ mTouchOffsetY = -handleHeight * 0.3f;
+ mHotspotY = 0;
+ mHeight = handleHeight;
+ invalidate();
}
@Override
@@ -7874,10 +7952,10 @@
final int[] coords = mTempCoords;
hostView.getLocationInWindow(coords);
final int posX = coords[0] + mPositionX + (int) mHotspotX;
- final int posY = coords[1] + mPositionY;
+ final int posY = coords[1] + mPositionY + (int) mHotspotY;
return posX >= clip.left && posX <= clip.right &&
- posY >= clip.top && posY + mHotspotY <= clip.bottom;
+ posY >= clip.top && posY <= clip.bottom;
}
private void moveTo(int x, int y) {
@@ -7900,8 +7978,8 @@
TextView.this.getLocationInWindow(coords);
}
if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
- mOffsetX += coords[0] - mLastParentX;
- mOffsetY += coords[1] - mLastParentY;
+ mTouchToWindowOffsetX += coords[0] - mLastParentX;
+ mTouchToWindowOffsetY += coords[1] - mLastParentY;
mLastParentX = coords[0];
mLastParentY = coords[1];
}
@@ -7930,8 +8008,8 @@
case MotionEvent.ACTION_DOWN: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
- mOffsetX = rawX - mPositionX;
- mOffsetY = rawY - mPositionY;
+ mTouchToWindowOffsetX = rawX - mPositionX;
+ mTouchToWindowOffsetY = rawY - mPositionY;
final int[] coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
mLastParentX = coords[0];
@@ -7942,8 +8020,8 @@
case MotionEvent.ACTION_MOVE: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
- final float newPosX = rawX - mOffsetX + mHotspotX;
- final float newPosY = rawY - mOffsetY + mHotspotY;
+ final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
+ final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY + mTouchOffsetY;
mController.updatePosition(this, (int) Math.round(newPosX),
(int) Math.round(newPosY));
@@ -7969,9 +8047,9 @@
final int lineBottom = mLayout.getLineBottom(line);
final Rect bounds = sCursorControllerTempRect;
- bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0)
+ bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - mHotspotX)
+ TextView.this.mScrollX;
- bounds.top = (bottom ? lineBottom : lineTop) + TextView.this.mScrollY;
+ bounds.top = (bottom ? lineBottom : lineTop - mHeight) + TextView.this.mScrollY;
bounds.right = bounds.left + width;
bounds.bottom = bounds.top + height;
@@ -7994,8 +8072,7 @@
};
InsertionPointCursorController() {
- Resources res = mContext.getResources();
- mHandle = new HandleView(this, res.getDrawable(mTextSelectHandleRes));
+ mHandle = new HandleView(this, HandleView.CENTER);
}
public void show() {
@@ -8070,9 +8147,8 @@
};
SelectionModifierCursorController() {
- Resources res = mContext.getResources();
- mStartHandle = new HandleView(this, res.getDrawable(mTextSelectHandleLeftRes));
- mEndHandle = new HandleView(this, res.getDrawable(mTextSelectHandleRightRes));
+ mStartHandle = new HandleView(this, HandleView.LEFT);
+ mEndHandle = new HandleView(this, HandleView.RIGHT);
}
public void show() {
@@ -8113,31 +8189,25 @@
// Handle the case where start and end are swapped, making sure start <= end
if (handle == mStartHandle) {
- if (offset <= selectionEnd) {
- if (selectionStart == offset) {
- return; // no change, no need to redraw;
- }
- selectionStart = offset;
- } else {
- selectionStart = selectionEnd;
- selectionEnd = offset;
- HandleView temp = mStartHandle;
- mStartHandle = mEndHandle;
- mEndHandle = temp;
+ if (selectionStart == offset || offset > selectionEnd) {
+ return; // no change, no need to redraw;
}
+ // If the user "closes" the selection entirely they were probably trying to
+ // select a single character. Help them out.
+ if (offset == selectionEnd) {
+ offset = selectionEnd - 1;
+ }
+ selectionStart = offset;
} else {
- if (offset >= selectionStart) {
- if (selectionEnd == offset) {
- return; // no change, no need to redraw;
- }
- selectionEnd = offset;
- } else {
- selectionEnd = selectionStart;
- selectionStart = offset;
- HandleView temp = mStartHandle;
- mStartHandle = mEndHandle;
- mEndHandle = temp;
+ if (selectionEnd == offset || offset < selectionStart) {
+ return; // no change, no need to redraw;
}
+ // If the user "closes" the selection entirely they were probably trying to
+ // select a single character. Help them out.
+ if (offset == selectionStart) {
+ offset = selectionStart + 1;
+ }
+ selectionEnd = offset;
}
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
@@ -8155,9 +8225,7 @@
return;
}
- boolean oneLineSelection = mLayout.getLineForOffset(selectionStart) ==
- mLayout.getLineForOffset(selectionEnd);
- mStartHandle.positionAtCursor(selectionStart, oneLineSelection);
+ mStartHandle.positionAtCursor(selectionStart, true);
mEndHandle.positionAtCursor(selectionEnd, true);
hideDelayed(DELAY_BEFORE_FADE_OUT);
}
@@ -8283,7 +8351,7 @@
final int previousLine = layout.getLineForOffset(previousOffset);
final int previousLineTop = layout.getLineTop(previousLine);
final int previousLineBottom = layout.getLineBottom(previousLine);
- final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 6;
+ final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 8;
// If new line is just before or after previous line and y position is less than
// hysteresisThreshold away from previous line, keep cursor on previous line.
@@ -8329,6 +8397,10 @@
private CursorController mSelectionModifierCursorController;
private ActionMode mSelectionActionMode;
private int mLastTouchOffset = -1;
+ // These are needed to desambiguate a long click. If the long click comes from ones of these, we
+ // select from the current cursor position. Otherwise, select from long pressed position.
+ private boolean mDPadCenterIsDown = false;
+ private boolean mEnterKeyIsDown = false;
// Created once and shared by different CursorController helper methods.
// Only one cursor controller is active at any time which prevent race conditions.
private static Rect sCursorControllerTempRect = new Rect();
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index e07c54f..8104ece 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -18,15 +18,17 @@
package com.android.internal.app;
import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.IActivityManager;
import android.app.ProgressDialog;
-import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetooth;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Handler;
import android.os.Power;
import android.os.PowerManager;
@@ -91,13 +93,20 @@
}
}
- Log.d(TAG, "Notifying thread to start radio shutdown");
+ final int longPressBehavior = context.getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnPowerBehavior);
+ final int resourceId = longPressBehavior == 2
+ ? com.android.internal.R.string.shutdown_confirm_question
+ : com.android.internal.R.string.shutdown_confirm;
+
+ Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
if (confirm) {
+ final CloseDialogReceiver closer = new CloseDialogReceiver(context);
final AlertDialog dialog = new AlertDialog.Builder(context)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(com.android.internal.R.string.power_off)
- .setMessage(com.android.internal.R.string.shutdown_confirm)
+ .setMessage(resourceId)
.setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
beginShutdownSequence(context);
@@ -105,6 +114,8 @@
})
.setNegativeButton(com.android.internal.R.string.no, null)
.create();
+ closer.dialog = dialog;
+ dialog.setOnDismissListener(closer);
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
if (!context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
@@ -116,6 +127,27 @@
}
}
+ private static class CloseDialogReceiver extends BroadcastReceiver
+ implements DialogInterface.OnDismissListener {
+ private Context mContext;
+ public Dialog dialog;
+
+ CloseDialogReceiver(Context context) {
+ mContext = context;
+ IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ context.registerReceiver(this, filter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ dialog.cancel();
+ }
+
+ public void onDismiss(DialogInterface unused) {
+ mContext.unregisterReceiver(this);
+ }
+ }
+
/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index d517d4c..eaeb67f 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -29,6 +29,7 @@
import android.os.Parcelable;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -77,16 +78,17 @@
private static final String VIEWS_TAG = "android:views";
+ private static final int THEME_SYSTEM_DEFAULT = 0;
+ private static final int THEME_APPLICATION = -1;
+ private static final int THEME_ALERT_DIALOG = -2;
+
// Order must be the same order as the TYPE_*
- // Special values:
- // 0: Use the system default theme
- // -1: Use the app's own theme
static final int THEME_RES_FOR_TYPE[] = new int[] {
com.android.internal.R.style.Theme_IconMenu,
com.android.internal.R.style.Theme_ExpandedMenu,
- com.android.internal.R.style.Theme_Light,
- -1,
- -1,
+ THEME_ALERT_DIALOG,
+ THEME_APPLICATION,
+ THEME_APPLICATION,
};
// Order must be the same order as the TYPE_*
@@ -205,7 +207,14 @@
private boolean mPreventDispatchingItemsChanged = false;
private boolean mOptionalIconsVisible = false;
-
+
+ private static int getAlertDialogTheme(Context context) {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
+ outValue, true);
+ return outValue.resourceId;
+ }
+
private MenuType[] mMenuTypes;
class MenuType {
private int mMenuType;
@@ -223,9 +232,20 @@
LayoutInflater getInflater() {
// Create an inflater that uses the given theme for the Views it inflates
if (mInflater == null) {
+ Context wrappedContext;
int themeResForType = THEME_RES_FOR_TYPE[mMenuType];
- Context wrappedContext = themeResForType < 0 ? mContext :
- new ContextThemeWrapper(mContext, themeResForType);
+ switch (themeResForType) {
+ case THEME_APPLICATION:
+ wrappedContext = new ContextThemeWrapper(mContext, themeResForType);
+ break;
+ case THEME_ALERT_DIALOG:
+ wrappedContext = new ContextThemeWrapper(mContext,
+ getAlertDialogTheme(mContext));
+ break;
+ default:
+ wrappedContext = mContext;
+ break;
+ }
mInflater = (LayoutInflater) wrappedContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
diff --git a/core/java/com/android/internal/widget/WeightedLinearLayout.java b/core/java/com/android/internal/widget/WeightedLinearLayout.java
index 3d09f08..385a7c3 100644
--- a/core/java/com/android/internal/widget/WeightedLinearLayout.java
+++ b/core/java/com/android/internal/widget/WeightedLinearLayout.java
@@ -30,8 +30,10 @@
* the available space.
*/
public class WeightedLinearLayout extends LinearLayout {
- private float mMajorWeight;
- private float mMinorWeight;
+ private float mMajorWeightMin;
+ private float mMinorWeightMin;
+ private float mMajorWeightMax;
+ private float mMinorWeightMax;
public WeightedLinearLayout(Context context) {
super(context);
@@ -43,8 +45,10 @@
TypedArray a =
context.obtainStyledAttributes(attrs, styleable.WeightedLinearLayout);
- mMajorWeight = a.getFloat(styleable.WeightedLinearLayout_majorWeight, 0.0f);
- mMinorWeight = a.getFloat(styleable.WeightedLinearLayout_minorWeight, 0.0f);
+ mMajorWeightMin = a.getFloat(styleable.WeightedLinearLayout_majorWeightMin, 0.0f);
+ mMinorWeightMin = a.getFloat(styleable.WeightedLinearLayout_minorWeightMin, 0.0f);
+ mMajorWeightMax = a.getFloat(styleable.WeightedLinearLayout_majorWeightMax, 0.0f);
+ mMinorWeightMax = a.getFloat(styleable.WeightedLinearLayout_minorWeightMax, 0.0f);
a.recycle();
}
@@ -60,17 +64,20 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
- int height = getMeasuredHeight();
boolean measure = false;
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, EXACTLY);
- final float widthWeight = isPortrait ? mMinorWeight : mMajorWeight;
- if (widthMode == AT_MOST && widthWeight > 0.0f) {
- if (width < (screenWidth * widthWeight)) {
- widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (screenWidth * widthWeight),
- EXACTLY);
+ final float widthWeightMin = isPortrait ? mMinorWeightMin : mMajorWeightMin;
+ final float widthWeightMax = isPortrait ? mMinorWeightMax : mMajorWeightMax;
+ if (widthMode == AT_MOST) {
+ final int weightedMin = (int) (screenWidth * widthWeightMin);
+ final int weightedMax = (int) (screenWidth * widthWeightMin);
+ if (widthWeightMin > 0.0f && width < weightedMin) {
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(weightedMin, EXACTLY);
+ measure = true;
+ } else if (widthWeightMax > 0.0f && width > weightedMax) {
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(weightedMax, EXACTLY);
measure = true;
}
}
@@ -78,7 +85,7 @@
// TODO: Support height?
if (measure) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 1b203ca..d2e5462 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -41,7 +41,7 @@
inline sp<Looper> getLooper() { return mLooper; }
- bool pollOnce(int timeoutMillis);
+ void pollOnce(int timeoutMillis);
void wake();
private:
@@ -61,8 +61,8 @@
NativeMessageQueue::~NativeMessageQueue() {
}
-bool NativeMessageQueue::pollOnce(int timeoutMillis) {
- return mLooper->pollOnce(timeoutMillis) != ALOOPER_POLL_TIMEOUT;
+void NativeMessageQueue::pollOnce(int timeoutMillis) {
+ mLooper->pollOnce(timeoutMillis);
}
void NativeMessageQueue::wake() {
@@ -112,24 +112,14 @@
jniThrowException(env, "java/lang/IllegalStateException", "Message queue not initialized");
}
-static jboolean android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
- jint timeoutMillis) {
- NativeMessageQueue* nativeMessageQueue =
- android_os_MessageQueue_getNativeMessageQueue(env, obj);
- if (! nativeMessageQueue) {
- throwQueueNotInitialized(env);
- return false;
- }
- return nativeMessageQueue->pollOnce(timeoutMillis);
+static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
+ jint ptr, jint timeoutMillis) {
+ NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
+ nativeMessageQueue->pollOnce(timeoutMillis);
}
-static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj) {
- NativeMessageQueue* nativeMessageQueue =
- android_os_MessageQueue_getNativeMessageQueue(env, obj);
- if (! nativeMessageQueue) {
- throwQueueNotInitialized(env);
- return;
- }
+static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
+ NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
return nativeMessageQueue->wake();
}
@@ -139,8 +129,8 @@
/* name, signature, funcPtr */
{ "nativeInit", "()V", (void*)android_os_MessageQueue_nativeInit },
{ "nativeDestroy", "()V", (void*)android_os_MessageQueue_nativeDestroy },
- { "nativePollOnce", "(I)Z", (void*)android_os_MessageQueue_nativePollOnce },
- { "nativeWake", "()V", (void*)android_os_MessageQueue_nativeWake }
+ { "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
+ { "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake }
};
#define FIND_CLASS(var, className) \
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..c0f0d167
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_disabled_focused_holo_light.png
new file mode 100644
index 0000000..ba03d28
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disabled_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_disabled_holo_dark.png
new file mode 100644
index 0000000..a320240
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disabled_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_disabled_holo_light.png
new file mode 100644
index 0000000..7f48c54
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_focused_holo_dark.png
new file mode 100644
index 0000000..82b7ba7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_focused_holo_light.png
new file mode 100644
index 0000000..69ecf05
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_normal_holo_dark.png
new file mode 100644
index 0000000..b81d4f9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_normal_holo_light.png
new file mode 100644
index 0000000..b74055e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
index 9f9cb01..c18e18b 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
index 56425d2..258c3d3 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..e63e5a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_disabled_focused_holo_light.png
new file mode 100644
index 0000000..37415e0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disabled_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_disabled_holo_dark.png
new file mode 100644
index 0000000..77a3115
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disabled_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_disabled_holo_light.png
new file mode 100644
index 0000000..51993e3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_focused_holo_dark.png
new file mode 100644
index 0000000..817adf7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_focused_holo_light.png
new file mode 100644
index 0000000..6459240
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_normal_holo_dark.png
new file mode 100644
index 0000000..bf4f3bb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_normal_holo_light.png
new file mode 100644
index 0000000..5a2a3c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
index 91e5f14..1333cb1 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
index 0cf7ed2..4413328 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png
index 3deb385..05d1668 100644
--- a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png
index de378a5..6f7eb42 100644
--- a/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png
index 35f8b3d..2c814f0 100644
--- a/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png
index 3f45375..a88bdf6 100644
--- a/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png
index ea58bf7..9a61d82 100644
--- a/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png
index b225aaff..56ca528 100644
--- a/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png
index b5b1533..6600035 100644
--- a/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png
index 81b8a75..11d31bb 100644
--- a/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
index eb8d85a..8c58c37 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
index 6777ebf..d543c66 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_dark.png
index 2a7505b..4fdf5ce 100644
--- a/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_light.png
index bbb01f0..e70f8c3 100644
--- a/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_disabled_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_dark.png
index b617a2a..c28d6cd 100644
--- a/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_light.png
index fd59f4a..ebf4da6 100644
--- a/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_disabled_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_dark.png
index 5d17cde..9a5455c 100644
--- a/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_light.png
index b6b4bf1..9648df2 100644
--- a/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_focused_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_dark.png
index eab5039..cd59fab 100644
--- a/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_light.png
index b6b4bf1..4da6192 100644
--- a/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_focused_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_dark.png
index edf2296..f18c6da 100644
--- a/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_light.png
index 68afa4c..70afefc 100644
--- a/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_normal_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_dark.png
index c7df168..fdf1586 100644
--- a/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_light.png
index 5a9087b..457038a6 100644
--- a/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_normal_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_dark.png
index 500490d..aa10966 100644
--- a/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_light.png
index f6690c6..8eaf738 100644
--- a/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_pressed_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_dark.png
index 933d2fe..674cc55 100644
--- a/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_light.png
index c07445a..b4f8800 100644
--- a/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_pressed_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_dark.png
new file mode 100644
index 0000000..15feef1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_light.png
new file mode 100644
index 0000000..0cff364
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_dark.png
new file mode 100644
index 0000000..f480729
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_light.png
new file mode 100644
index 0000000..1c632e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_dark.png
new file mode 100644
index 0000000..2dd3d77
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_focused_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_light.png
new file mode 100644
index 0000000..7b10118
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_normal_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_dark.png
new file mode 100644
index 0000000..2f863bb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_normal_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_light.png
new file mode 100644
index 0000000..1220c20
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index 128a8dd..5a8c8e5 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index da05c23..2263153 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
index da66a98..dbfa16a 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
index 3ac8417..47a43e9 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
index fc9d493..2787a4b 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
index 315ae3b..c8bf8b1 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
index ee9590c6..eb4f17a 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
index cbc9da2c..42b434c 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
index 1792063..e362aa1 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
index 097025b..cc61414 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index 5b92d7c6..8b813b9 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index a244f45..54686cd 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
index 9218f91..056f451 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
index 81802f8..2c4a6dd 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
index 9dea983..127a9be 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
index fc2374b..4853ef4 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
index 18bb6bd..d767185 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
index de78a9f..00e6105 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
index 2269326..293cad3 100755
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_pressed_holo_light.9.png
new file mode 100644
index 0000000..6963a0e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_toggle_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/cab_divider_holo_dark.png b/core/res/res/drawable-hdpi/cab_divider_holo_dark.png
index e6f61fc..e2c2119 100755
--- a/core/res/res/drawable-hdpi/cab_divider_holo_dark.png
+++ b/core/res/res/drawable-hdpi/cab_divider_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/cab_divider_holo_light.png b/core/res/res/drawable-hdpi/cab_divider_holo_light.png
index 2f97a29..51e2295 100755
--- a/core/res/res/drawable-hdpi/cab_divider_holo_light.png
+++ b/core/res/res/drawable-hdpi/cab_divider_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/cab_holo_dark.9.png b/core/res/res/drawable-hdpi/cab_holo_dark.9.png
index 662d63c..64e2052 100755
--- a/core/res/res/drawable-hdpi/cab_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/cab_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/cab_holo_light.9.png b/core/res/res/drawable-hdpi/cab_holo_light.9.png
index e8cbde1..4f2afcf 100755
--- a/core/res/res/drawable-hdpi/cab_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/cab_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/cab_ic_close_focused_holo.png b/core/res/res/drawable-hdpi/cab_ic_close_focused_holo.png
index 861e0a1..9d7f932 100755
--- a/core/res/res/drawable-hdpi/cab_ic_close_focused_holo.png
+++ b/core/res/res/drawable-hdpi/cab_ic_close_focused_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/cab_ic_close_normal_holo.png b/core/res/res/drawable-hdpi/cab_ic_close_normal_holo.png
index 036f362..641507d 100755
--- a/core/res/res/drawable-hdpi/cab_ic_close_normal_holo.png
+++ b/core/res/res/drawable-hdpi/cab_ic_close_normal_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/cab_ic_close_pressed_holo.png b/core/res/res/drawable-hdpi/cab_ic_close_pressed_holo.png
index be8c2ff..ebb0fc8 100755
--- a/core/res/res/drawable-hdpi/cab_ic_close_pressed_holo.png
+++ b/core/res/res/drawable-hdpi/cab_ic_close_pressed_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
new file mode 100644
index 0000000..83c0852
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
new file mode 100644
index 0000000..c495216
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..620adaa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
new file mode 100644
index 0000000..b03d6cd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_ic_close_focused_holo_dark.png b/core/res/res/drawable-hdpi/dialog_ic_close_focused_holo_dark.png
new file mode 100644
index 0000000..785ae6e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_ic_close_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_ic_close_focused_holo_light.png b/core/res/res/drawable-hdpi/dialog_ic_close_focused_holo_light.png
new file mode 100644
index 0000000..d96787b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_ic_close_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_ic_close_normal_holo_dark.png b/core/res/res/drawable-hdpi/dialog_ic_close_normal_holo_dark.png
new file mode 100644
index 0000000..d042a81
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_ic_close_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_ic_close_normal_holo_light.png b/core/res/res/drawable-hdpi/dialog_ic_close_normal_holo_light.png
new file mode 100644
index 0000000..677cf3d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_ic_close_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_ic_close_pressed_holo_dark.png b/core/res/res/drawable-hdpi/dialog_ic_close_pressed_holo_dark.png
new file mode 100644
index 0000000..9b13c5b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_ic_close_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_ic_close_pressed_holo_light.png b/core/res/res/drawable-hdpi/dialog_ic_close_pressed_holo_light.png
new file mode 100644
index 0000000..8e245fc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_ic_close_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
new file mode 100644
index 0000000..cffae3e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
new file mode 100644
index 0000000..0394885
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
new file mode 100644
index 0000000..6746ce8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
new file mode 100644
index 0000000..bdcdc71
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/dropdown_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..519f522
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/dropdown_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..9c181d0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/dropdown_disabled_holo_dark.9.png
new file mode 100644
index 0000000..6ca975f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/dropdown_disabled_holo_light.9.png
new file mode 100644
index 0000000..7a20af7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/dropdown_focused_holo_dark.9.png
new file mode 100644
index 0000000..a3dfb98
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_focused_holo_light.9.png b/core/res/res/drawable-hdpi/dropdown_focused_holo_light.9.png
new file mode 100644
index 0000000..766543c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_focused_holo_dark.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..53f02576
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_focused_holo_light.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_focused_holo_light.png
new file mode 100644
index 0000000..0daee9b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_holo_dark.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_holo_dark.png
new file mode 100644
index 0000000..b659926
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_holo_light.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_holo_light.png
new file mode 100644
index 0000000..e22dbfd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_focused_holo_dark.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_focused_holo_dark.png
new file mode 100644
index 0000000..0f65227
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_focused_holo_light.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_focused_holo_light.png
new file mode 100644
index 0000000..9c47d7e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_normal_holo_dark.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_normal_holo_dark.png
new file mode 100644
index 0000000..06e5b47
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_normal_holo_light.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_normal_holo_light.png
new file mode 100644
index 0000000..d362ec1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_pressed_holo_dark.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_pressed_holo_dark.png
new file mode 100644
index 0000000..d010995
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_ic_arrow_pressed_holo_light.png b/core/res/res/drawable-hdpi/dropdown_ic_arrow_pressed_holo_light.png
new file mode 100644
index 0000000..b95f94b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_ic_arrow_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/dropdown_normal_holo_dark.9.png
new file mode 100644
index 0000000..a4ac317
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_normal_holo_light.9.png b/core/res/res/drawable-hdpi/dropdown_normal_holo_light.9.png
new file mode 100644
index 0000000..b4ab9ad
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/dropdown_pressed_holo_dark.9.png
new file mode 100644
index 0000000..f6382c8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dropdown_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/dropdown_pressed_holo_light.9.png
new file mode 100644
index 0000000..c849e2f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dropdown_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
new file mode 100644
index 0000000..061f80a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
new file mode 100644
index 0000000..d818806
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644
index 0000000..8563c1a8d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644
index 0000000..1cd2384
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_divider_horizontal_holo_dark.9.png b/core/res/res/drawable-hdpi/list_divider_horizontal_holo_dark.9.png
new file mode 100644
index 0000000..0a4347f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_divider_horizontal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_section_header_holo_dark.9.png b/core/res/res/drawable-hdpi/list_section_header_holo_dark.9.png
new file mode 100644
index 0000000..2030d3b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_section_header_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_section_header_holo_light.9.png b/core/res/res/drawable-hdpi/list_section_header_holo_light.9.png
new file mode 100644
index 0000000..4ca2773
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_section_header_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_activated_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selector_activated_holo_dark.9.png
new file mode 100644
index 0000000..1a516c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_activated_holo_light.9.png b/core/res/res/drawable-hdpi/list_selector_activated_holo_light.9.png
new file mode 100644
index 0000000..f22217b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selector_disabled_holo_dark.9.png
new file mode 100644
index 0000000..f6fd30d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/list_selector_disabled_holo_light.9.png
new file mode 100644
index 0000000..ca8e9a2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selector_focused_holo_dark.9.png
new file mode 100644
index 0000000..c1f3d7d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_focused_holo_light.9.png b/core/res/res/drawable-hdpi/list_selector_focused_holo_light.9.png
new file mode 100644
index 0000000..99bb246
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_multiselect_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selector_multiselect_holo_dark.9.png
new file mode 100644
index 0000000..f702fc8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_multiselect_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_multiselect_holo_light.9.png b/core/res/res/drawable-hdpi/list_selector_multiselect_holo_light.9.png
new file mode 100644
index 0000000..e8f277d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_multiselect_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selector_pressed_holo_dark.9.png
new file mode 100644
index 0000000..0ed5ba3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_selector_pressed_holo_light.9.png
new file mode 100644
index 0000000..1471c17
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
new file mode 100644
index 0000000..7ec3a33f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
new file mode 100644
index 0000000..da1fe94
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowdown_left_holo_dark.9.png b/core/res/res/drawable-hdpi/quickactions_arrowdown_left_holo_dark.9.png
new file mode 100644
index 0000000..93a8417
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowdown_left_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowdown_left_holo_light.9.png b/core/res/res/drawable-hdpi/quickactions_arrowdown_left_holo_light.9.png
new file mode 100644
index 0000000..61e856a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowdown_left_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowdown_right_holo_dark.9.png b/core/res/res/drawable-hdpi/quickactions_arrowdown_right_holo_dark.9.png
new file mode 100644
index 0000000..7632a16
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowdown_right_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowdown_right_holo_light.9.png b/core/res/res/drawable-hdpi/quickactions_arrowdown_right_holo_light.9.png
new file mode 100644
index 0000000..8e66ad1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowdown_right_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowup_left_holo_dark.9.png b/core/res/res/drawable-hdpi/quickactions_arrowup_left_holo_dark.9.png
new file mode 100644
index 0000000..02618ca
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowup_left_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowup_left_holo_light.9.png b/core/res/res/drawable-hdpi/quickactions_arrowup_left_holo_light.9.png
new file mode 100644
index 0000000..939050d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowup_left_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowup_left_right_holo_dark.9.png b/core/res/res/drawable-hdpi/quickactions_arrowup_left_right_holo_dark.9.png
new file mode 100644
index 0000000..f5cf487
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowup_left_right_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickactions_arrowup_right_holo_light.9.png b/core/res/res/drawable-hdpi/quickactions_arrowup_right_holo_light.9.png
new file mode 100644
index 0000000..1237f26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/quickactions_arrowup_right_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/screen_progress_frame.9.png b/core/res/res/drawable-hdpi/screen_progress_frame.9.png
deleted file mode 100644
index 3f9d738..0000000
--- a/core/res/res/drawable-hdpi/screen_progress_frame.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/screen_progress_inner.9.png b/core/res/res/drawable-hdpi/screen_progress_inner.9.png
deleted file mode 100644
index 10c7da5..0000000
--- a/core/res/res/drawable-hdpi/screen_progress_inner.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_holo.png b/core/res/res/drawable-hdpi/scrubber_control_holo.png
new file mode 100644
index 0000000..3a72307
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_control_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_track_holo_dark.9.png b/core/res/res/drawable-hdpi/scrubber_track_holo_dark.9.png
new file mode 100644
index 0000000..e6d7123
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_track_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_track_holo_light.9.png b/core/res/res/drawable-hdpi/scrubber_track_holo_light.9.png
new file mode 100644
index 0000000..f75bfa0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_track_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left.png b/core/res/res/drawable-hdpi/text_select_handle_left.png
old mode 100644
new mode 100755
index 271a6d0..3743d91
--- a/core/res/res/drawable-hdpi/text_select_handle_left.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_middle.png b/core/res/res/drawable-hdpi/text_select_handle_middle.png
old mode 100644
new mode 100755
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right.png b/core/res/res/drawable-hdpi/text_select_handle_right.png
old mode 100644
new mode 100755
index dfdf899..12a3dff
--- a/core/res/res/drawable-hdpi/text_select_handle_right.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_dark.png
deleted file mode 100644
index 3fac4aa..0000000
--- a/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_light.png
deleted file mode 100644
index 3da9a46..0000000
--- a/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_disable_holo_dark.png
deleted file mode 100644
index 3fac4aa..0000000
--- a/core/res/res/drawable-mdpi/btn_check_off_disable_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_disable_holo_light.png
deleted file mode 100644
index 3da9a46..0000000
--- a/core/res/res/drawable-mdpi/btn_check_off_disable_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..7e58392
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_disabled_focused_holo_light.png
new file mode 100644
index 0000000..d5c1f7c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disabled_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_disabled_holo_dark.png
new file mode 100644
index 0000000..b6eec97
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disabled_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_disabled_holo_light.png
new file mode 100644
index 0000000..1bc34b6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_focused_holo_dark.png
new file mode 100644
index 0000000..894836f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_focused_holo_light.png
new file mode 100644
index 0000000..ae81a5e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_normal_holo_dark.png
new file mode 100644
index 0000000..5434614
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_normal_holo_light.png
new file mode 100644
index 0000000..0d43dc4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
index 0dcb9de..0f9f4f0 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
index b25fdc4..77ad452 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..28bf7f6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_disabled_focused_holo_light.png
new file mode 100644
index 0000000..bb2d314
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disabled_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_disabled_holo_dark.png
new file mode 100644
index 0000000..8cf4554
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disabled_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_disabled_holo_light.png
new file mode 100644
index 0000000..ba37f93
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_focused_holo_dark.png
new file mode 100644
index 0000000..1fca094
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_focused_holo_light.png
new file mode 100644
index 0000000..21c33f0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_normal_holo_dark.png
new file mode 100644
index 0000000..e65c0b4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_normal_holo_light.png
new file mode 100644
index 0000000..9576bea
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
index 0722cda..84733fb 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
index 4de166e..67a15d2 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png
index 9bc1ee8..15003be 100644
--- a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png
index cc643ea..573f197 100644
--- a/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png
index 0586d52..953a553 100644
--- a/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png
index dd6c1a0..d79a61e 100644
--- a/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png
index e8f07cb..897676e 100644
--- a/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png
index 0685f1e..b485925 100644
--- a/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png
index 6b33fa4..1cdbf66 100644
--- a/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png
index eb728ed..ab7eb54 100644
--- a/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
index 4a15d9d..d95ef6d 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
index 6718ff7..60ed4fc 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_dark.png
index f21142e..f937182 100644
--- a/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_light.png
index a1031fc..4c35fb3 100644
--- a/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_disabled_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_dark.png
index 61243c5..af38a4f 100644
--- a/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_light.png
index faa55e0..a368602 100644
--- a/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_disabled_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_dark.png
index 0c645da..695d0b9 100644
--- a/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_light.png
index 5efc321..6467bea 100644
--- a/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_focused_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_dark.png
index 96bcdc5..813a069 100644
--- a/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_light.png
index 5efc321..fe80d69 100644
--- a/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_focused_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_dark.png
index 96413ef..5b6d906 100644
--- a/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_light.png
index 1cb5432..e5132ef 100644
--- a/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_normal_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_dark.png
index 2e8404a..e216d35 100644
--- a/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_light.png
index b3e14b1..ed3946a 100644
--- a/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_normal_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_dark.png
index 5f74c70..9ab32d1 100644
--- a/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_light.png
index 408e50e..7175853 100644
--- a/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_pressed_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_dark.png
index ff60bc2..a6fa7b6 100644
--- a/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_light.png
index 2125c24..e7a634d 100644
--- a/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_pressed_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_dark.png
new file mode 100644
index 0000000..153e50d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_light.png
new file mode 100644
index 0000000..379fd24
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_off_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_dark.png
new file mode 100644
index 0000000..fe35f1c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_light.png
new file mode 100644
index 0000000..002237f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_off_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_dark.png
new file mode 100644
index 0000000..0ad2583
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_focused_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_light.png
new file mode 100644
index 0000000..ce7c3b4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_on_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_normal_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_dark.png
new file mode 100644
index 0000000..ee93e88
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_normal_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_light.png
new file mode 100644
index 0000000..597fd9a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_star_on_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index 7d1e16d..deecc51 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index 92e86cd..76d4f05 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
index 1cf473b..0ecd1ae 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
index d6f2125..a7015ee 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
index 31f7f8c..71949b2 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
index 82425d5..351f76b 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
index 16f19fc..44b9503 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
index e2c7702..d70a1fc5 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
index d61470c..5f9d2b1 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
index 4019fee..6723757 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index ba354e3..62b67a5 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index 9391b2e..b8418bc 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
index 601ff2c..f9a11a5 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
index 90c259a..e983c8a 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
index 857c757..ed8407b 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
index ef16a48..31f36b7 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
index d47ec8f..e023c44 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
index 2951caf..e4008cf 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
index 141b4dd..56e1157 100755
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_pressed_holo_light.9.png
new file mode 100644
index 0000000..b6508fc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_toggle_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cab_divider_holo_dark.png b/core/res/res/drawable-mdpi/cab_divider_holo_dark.png
index 57cc8a4..317263a 100755
--- a/core/res/res/drawable-mdpi/cab_divider_holo_dark.png
+++ b/core/res/res/drawable-mdpi/cab_divider_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cab_divider_holo_light.png b/core/res/res/drawable-mdpi/cab_divider_holo_light.png
index ec85701..824ad27 100755
--- a/core/res/res/drawable-mdpi/cab_divider_holo_light.png
+++ b/core/res/res/drawable-mdpi/cab_divider_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cab_holo_dark.9.png b/core/res/res/drawable-mdpi/cab_holo_dark.9.png
index 6c85300..7daae1f 100755
--- a/core/res/res/drawable-mdpi/cab_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/cab_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cab_holo_light.9.png b/core/res/res/drawable-mdpi/cab_holo_light.9.png
index c82352a..0e64c5c 100755
--- a/core/res/res/drawable-mdpi/cab_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/cab_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cab_ic_close_focused_holo.png b/core/res/res/drawable-mdpi/cab_ic_close_focused_holo.png
index df170c4..59149e4 100755
--- a/core/res/res/drawable-mdpi/cab_ic_close_focused_holo.png
+++ b/core/res/res/drawable-mdpi/cab_ic_close_focused_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cab_ic_close_normal_holo.png b/core/res/res/drawable-mdpi/cab_ic_close_normal_holo.png
index 9482ce7..b378885 100755
--- a/core/res/res/drawable-mdpi/cab_ic_close_normal_holo.png
+++ b/core/res/res/drawable-mdpi/cab_ic_close_normal_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/cab_ic_close_pressed_holo.png b/core/res/res/drawable-mdpi/cab_ic_close_pressed_holo.png
index d115d20..29b0407 100755
--- a/core/res/res/drawable-mdpi/cab_ic_close_pressed_holo.png
+++ b/core/res/res/drawable-mdpi/cab_ic_close_pressed_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
new file mode 100644
index 0000000..e3a30a9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
new file mode 100644
index 0000000..f7f344a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..26bf28a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
new file mode 100644
index 0000000..0edfe85
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_ic_close_focused_holo_dark.png b/core/res/res/drawable-mdpi/dialog_ic_close_focused_holo_dark.png
new file mode 100644
index 0000000..4f08fb4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_ic_close_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_ic_close_focused_holo_light.png b/core/res/res/drawable-mdpi/dialog_ic_close_focused_holo_light.png
new file mode 100644
index 0000000..cc535bd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_ic_close_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_ic_close_normal_holo_dark.png b/core/res/res/drawable-mdpi/dialog_ic_close_normal_holo_dark.png
new file mode 100644
index 0000000..9d3e5b9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_ic_close_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_ic_close_normal_holo_light.png b/core/res/res/drawable-mdpi/dialog_ic_close_normal_holo_light.png
new file mode 100644
index 0000000..74aff55
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_ic_close_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_ic_close_pressed_holo_dark.png b/core/res/res/drawable-mdpi/dialog_ic_close_pressed_holo_dark.png
new file mode 100644
index 0000000..c7f7699
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_ic_close_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_ic_close_pressed_holo_light.png b/core/res/res/drawable-mdpi/dialog_ic_close_pressed_holo_light.png
new file mode 100644
index 0000000..a10f9a6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_ic_close_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
new file mode 100644
index 0000000..51e7ec3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
new file mode 100644
index 0000000..c4b70625a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
new file mode 100644
index 0000000..7f97eae
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
new file mode 100644
index 0000000..341bb4b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/dropdown_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..d9ad9d3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/dropdown_disabled_focused_holo_light.9.png
new file mode 100644
index 0000000..3d82dc6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/dropdown_disabled_holo_dark.9.png
new file mode 100644
index 0000000..15e2993
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/dropdown_disabled_holo_light.9.png
new file mode 100644
index 0000000..4831556
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/dropdown_focused_holo_dark.9.png
new file mode 100644
index 0000000..4021da8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_focused_holo_light.9.png b/core/res/res/drawable-mdpi/dropdown_focused_holo_light.9.png
new file mode 100644
index 0000000..120fe9a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_focused_holo_dark.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_focused_holo_dark.png
new file mode 100644
index 0000000..d2b3557
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_focused_holo_light.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_focused_holo_light.png
new file mode 100644
index 0000000..cf50169
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_holo_dark.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_holo_dark.png
new file mode 100644
index 0000000..2663411
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_holo_light.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_holo_light.png
new file mode 100644
index 0000000..def24e4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_focused_holo_dark.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_focused_holo_dark.png
new file mode 100644
index 0000000..9196b72
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_focused_holo_light.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_focused_holo_light.png
new file mode 100644
index 0000000..85372b9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_normal_holo_dark.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_normal_holo_dark.png
new file mode 100644
index 0000000..566be42
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_normal_holo_light.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_normal_holo_light.png
new file mode 100644
index 0000000..e600500
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_pressed_holo_dark.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_pressed_holo_dark.png
new file mode 100644
index 0000000..ef21dc2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_ic_arrow_pressed_holo_light.png b/core/res/res/drawable-mdpi/dropdown_ic_arrow_pressed_holo_light.png
new file mode 100644
index 0000000..52fc112
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_ic_arrow_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/dropdown_normal_holo_dark.9.png
new file mode 100644
index 0000000..a5da0cd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_normal_holo_light.9.png b/core/res/res/drawable-mdpi/dropdown_normal_holo_light.9.png
new file mode 100644
index 0000000..6695af9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/dropdown_pressed_holo_dark.9.png
new file mode 100644
index 0000000..e7e70fb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dropdown_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/dropdown_pressed_holo_light.9.png
new file mode 100644
index 0000000..f760c88
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dropdown_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_emergency.png b/core/res/res/drawable-mdpi/ic_emergency.png
index 45d0f21..c6faf1e 100755
--- a/core/res/res/drawable-mdpi/ic_emergency.png
+++ b/core/res/res/drawable-mdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
new file mode 100644
index 0000000..6f87b11
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
new file mode 100644
index 0000000..04dac38
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644
index 0000000..5580af6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644
index 0000000..fc2081a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_section_header_holo_dark.9.png b/core/res/res/drawable-mdpi/list_section_header_holo_dark.9.png
new file mode 100644
index 0000000..48dfea0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_section_header_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_section_header_holo_light.9.png b/core/res/res/drawable-mdpi/list_section_header_holo_light.9.png
new file mode 100644
index 0000000..36a046b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_section_header_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_activated_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selector_activated_holo_dark.9.png
new file mode 100644
index 0000000..66bc259
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_activated_holo_light.9.png b/core/res/res/drawable-mdpi/list_selector_activated_holo_light.9.png
new file mode 100644
index 0000000..c5822b1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selector_disabled_holo_dark.9.png
new file mode 100644
index 0000000..92da2f0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/list_selector_disabled_holo_light.9.png
new file mode 100644
index 0000000..42cb646
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selector_focused_holo_dark.9.png
new file mode 100644
index 0000000..eb4555d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_focused_holo_light.9.png b/core/res/res/drawable-mdpi/list_selector_focused_holo_light.9.png
new file mode 100644
index 0000000..d799fbf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_multiselect_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selector_multiselect_holo_dark.9.png
new file mode 100644
index 0000000..2c3647e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_multiselect_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_multiselect_holo_light.9.png b/core/res/res/drawable-mdpi/list_selector_multiselect_holo_light.9.png
new file mode 100644
index 0000000..860c58e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_multiselect_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selector_pressed_holo_dark.9.png
new file mode 100644
index 0000000..bf36a43
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selector_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_selector_pressed_holo_light.9.png
new file mode 100644
index 0000000..0f0be2a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_selector_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
new file mode 100644
index 0000000..7d5c10c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
new file mode 100644
index 0000000..a0d3094d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowdown_left_holo_dark.9.png b/core/res/res/drawable-mdpi/quickactions_arrowdown_left_holo_dark.9.png
new file mode 100644
index 0000000..ece6551
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowdown_left_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowdown_left_holo_light.9.png b/core/res/res/drawable-mdpi/quickactions_arrowdown_left_holo_light.9.png
new file mode 100644
index 0000000..819656f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowdown_left_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowdown_right_holo_dark.9.png b/core/res/res/drawable-mdpi/quickactions_arrowdown_right_holo_dark.9.png
new file mode 100644
index 0000000..8e95970
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowdown_right_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowdown_right_holo_light.9.png b/core/res/res/drawable-mdpi/quickactions_arrowdown_right_holo_light.9.png
new file mode 100644
index 0000000..d5bef51
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowdown_right_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowup_left_holo_dark.9.png b/core/res/res/drawable-mdpi/quickactions_arrowup_left_holo_dark.9.png
new file mode 100644
index 0000000..543e341
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowup_left_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowup_left_holo_light.9.png b/core/res/res/drawable-mdpi/quickactions_arrowup_left_holo_light.9.png
new file mode 100644
index 0000000..e40e91d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowup_left_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowup_left_right_holo_dark.9.png b/core/res/res/drawable-mdpi/quickactions_arrowup_left_right_holo_dark.9.png
new file mode 100644
index 0000000..a4617e7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowup_left_right_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickactions_arrowup_right_holo_light.9.png b/core/res/res/drawable-mdpi/quickactions_arrowup_right_holo_light.9.png
new file mode 100644
index 0000000..1e8e7a06
--- /dev/null
+++ b/core/res/res/drawable-mdpi/quickactions_arrowup_right_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/screen_progress_frame.9.png b/core/res/res/drawable-mdpi/screen_progress_frame.9.png
deleted file mode 100644
index 0e92429..0000000
--- a/core/res/res/drawable-mdpi/screen_progress_frame.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/screen_progress_inner.9.png b/core/res/res/drawable-mdpi/screen_progress_inner.9.png
deleted file mode 100644
index 1799a53..0000000
--- a/core/res/res/drawable-mdpi/screen_progress_inner.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_holo.png b/core/res/res/drawable-mdpi/scrubber_control_holo.png
new file mode 100644
index 0000000..135b2aa
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_control_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_holo_dark.9.png b/core/res/res/drawable-mdpi/scrubber_track_holo_dark.9.png
new file mode 100644
index 0000000..7b48cf9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_track_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_holo_light.9.png b/core/res/res/drawable-mdpi/scrubber_track_holo_light.9.png
new file mode 100644
index 0000000..7c84ac9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_track_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_holo_dark.xml b/core/res/res/drawable/btn_check_holo_dark.xml
index fd85d72..a163c2e 100644
--- a/core/res/res/drawable/btn_check_holo_dark.xml
+++ b/core/res/res/drawable/btn_check_holo_dark.xml
@@ -50,16 +50,16 @@
<!-- Disabled states -->
<item android:state_checked="true" android:state_window_focused="false"
- android:drawable="@drawable/btn_check_on_disable_holo_dark" />
+ android:drawable="@drawable/btn_check_on_disabled_holo_dark" />
<item android:state_checked="false" android:state_window_focused="false"
- android:drawable="@drawable/btn_check_off_disable_holo_dark" />
+ android:drawable="@drawable/btn_check_off_disabled_holo_dark" />
<item android:state_checked="true" android:state_focused="true"
- android:drawable="@drawable/btn_check_on_disable_focused_holo_dark" />
+ android:drawable="@drawable/btn_check_on_disabled_focused_holo_dark" />
<item android:state_checked="false" android:state_focused="true"
- android:drawable="@drawable/btn_check_off_disable_focused_holo_dark" />
+ android:drawable="@drawable/btn_check_off_disabled_focused_holo_dark" />
- <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable_holo_dark" />
- <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable_holo_dark" />
+ <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disabled_holo_dark" />
+ <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disabled_holo_dark" />
</selector>
diff --git a/core/res/res/drawable/btn_check_holo_light.xml b/core/res/res/drawable/btn_check_holo_light.xml
index 4fb16fa..5c49456 100644
--- a/core/res/res/drawable/btn_check_holo_light.xml
+++ b/core/res/res/drawable/btn_check_holo_light.xml
@@ -50,16 +50,16 @@
<!-- Disabled states -->
<item android:state_checked="true" android:state_window_focused="false"
- android:drawable="@drawable/btn_check_on_disable_holo_light" />
+ android:drawable="@drawable/btn_check_on_disabled_holo_light" />
<item android:state_checked="false" android:state_window_focused="false"
- android:drawable="@drawable/btn_check_off_disable_holo_light" />
+ android:drawable="@drawable/btn_check_off_disabled_holo_light" />
<item android:state_checked="true" android:state_focused="true"
- android:drawable="@drawable/btn_check_on_disable_focused_holo_light" />
+ android:drawable="@drawable/btn_check_on_disabled_focused_holo_light" />
<item android:state_checked="false" android:state_focused="true"
- android:drawable="@drawable/btn_check_off_disable_focused_holo_light" />
+ android:drawable="@drawable/btn_check_off_disabled_focused_holo_light" />
- <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable_holo_light" />
- <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable_holo_light" />
+ <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disabled_holo_light" />
+ <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disabled_holo_light" />
</selector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
new file mode 100644
index 0000000..4691edf
--- /dev/null
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_dark.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_dark" />
+ <item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
new file mode 100644
index 0000000..5c52ff4
--- /dev/null
+++ b/core/res/res/drawable/ic_menu_moreoverflow_holo_light.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:drawable="@drawable/ic_menu_moreoverflow_focused_holo_light" />
+ <item android:drawable="@drawable/ic_menu_moreoverflow_normal_holo_light" />
+</selector>
diff --git a/core/res/res/drawable/list_selector_holo_dark.xml b/core/res/res/drawable/list_selector_holo_dark.xml
new file mode 100644
index 0000000..ee59904
--- /dev/null
+++ b/core/res/res/drawable/list_selector_holo_dark.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_window_focused="false" android:drawable="@color/transparent" />
+
+ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+ <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
+ <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
+ <item android:state_focused="true" android:drawable="@drawable/list_selector_focused_holo_dark" />
+ <item android:drawable="@drawable/list_selector_focused_holo_dark" />
+
+</selector>
diff --git a/core/res/res/drawable/list_selector_holo_light.xml b/core/res/res/drawable/list_selector_holo_light.xml
new file mode 100644
index 0000000..2dc39f6
--- /dev/null
+++ b/core/res/res/drawable/list_selector_holo_light.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_window_focused="false" android:drawable="@color/transparent" />
+
+ <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+ <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
+ <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
+ <item android:state_focused="true" android:drawable="@drawable/list_selector_focused_holo_light" />
+ <item android:drawable="@drawable/list_selector_focused_holo_light" />
+
+</selector>
diff --git a/core/res/res/drawable/screen_progress.xml b/core/res/res/drawable/screen_progress.xml
deleted file mode 100644
index aed23a6..0000000
--- a/core/res/res/drawable/screen_progress.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/progress.xml
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@android:drawable/screen_progress_frame" />
- <item>
- <scale scaleWidth="100%" scaleGravity="0x3" drawable="@android:drawable/screen_progress_inner" />
- </item>
-</layer-list>
-
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml b/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
new file mode 100644
index 0000000..90172a5
--- /dev/null
+++ b/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:id="@android:id/background"
+ android:drawable="@android:drawable/scrubber_track_holo_dark" />
+ <item android:id="@android:id/secondaryProgress"
+ android:drawable="@android:drawable/scrubber_track_holo_dark" />
+ <item android:id="@android:id/progress"
+ android:drawable="@android:drawable/scrubber_track_holo_dark" />
+</layer-list>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml b/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
new file mode 100644
index 0000000..5fc9697
--- /dev/null
+++ b/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:id="@android:id/background"
+ android:drawable="@android:drawable/scrubber_track_holo_light" />
+ <item android:id="@android:id/secondaryProgress"
+ android:drawable="@android:drawable/scrubber_track_holo_light" />
+ <item android:id="@android:id/progress"
+ android:drawable="@android:drawable/scrubber_track_holo_light" />
+</layer-list>
diff --git a/core/res/res/layout-xlarge/alert_dialog.xml b/core/res/res/layout-xlarge/alert_dialog.xml
new file mode 100644
index 0000000..5291e9d
--- /dev/null
+++ b/core/res/res/layout-xlarge/alert_dialog.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.internal.widget.WeightedLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingTop="9dip"
+ android:paddingBottom="3dip"
+ android:paddingLeft="3dip"
+ android:paddingRight="1dip"
+ android:majorWeightMin="0.45"
+ android:minorWeightMin="0.72"
+ android:majorWeightMax="0.45"
+ android:minorWeightMax="0.72">
+
+ <LinearLayout android:id="@+id/topPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="54dip"
+ android:orientation="vertical">
+ <LinearLayout android:id="@+id/title_template"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="9dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingTop="6dip"
+ android:paddingRight="10dip"
+ android:src="@drawable/ic_dialog_info" />
+ <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+ style="?android:attr/textAppearanceLarge"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+ <ImageView android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:visibility="gone"
+ android:scaleType="fitXY"
+ android:gravity="fill_horizontal"
+ android:src="@android:drawable/divider_horizontal_dark" />
+ <!-- If the client uses a customTitle, it will be added here. -->
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/contentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <ScrollView android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dip"
+ android:paddingBottom="12dip"
+ android:paddingLeft="14dip"
+ android:paddingRight="10dip">
+ <TextView android:id="@+id/message"
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="5dip" />
+ </ScrollView>
+ </LinearLayout>
+
+ <FrameLayout android:id="@+id/customPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+ <FrameLayout android:id="@+android:id/custom"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dip"
+ android:paddingBottom="5dip" />
+ </FrameLayout>
+
+ <LinearLayout android:id="@+id/buttonPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="54dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingTop="4dip"
+ android:paddingLeft="2dip"
+ android:paddingRight="2dip"
+ android:measureWithLargestChild="true">
+ <LinearLayout android:id="@+id/leftSpacer"
+ android:layout_weight="0.25"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone" />
+ <Button android:id="@+id/button1"
+ android:layout_width="0dip"
+ android:layout_gravity="left"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button3"
+ android:layout_width="0dip"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button2"
+ android:layout_width="0dip"
+ android:layout_gravity="right"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:layout_height="wrap_content" />
+ <LinearLayout android:id="@+id/rightSpacer"
+ android:layout_width="0dip"
+ android:layout_weight="0.25"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone" />
+ </LinearLayout>
+ </LinearLayout>
+</com.android.internal.widget.WeightedLinearLayout>
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index b746d28..541d84d 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -28,8 +28,9 @@
android:paddingBottom="3dip"
android:paddingLeft="3dip"
android:paddingRight="1dip"
- android:majorWeight="0.65"
- android:minorWeight="0.9">
+ android:majorWeightMin="0.65"
+ android:minorWeightMin="0.9"
+ android:majorWeightMax="0.65">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/fragment_bread_crumb_item.xml b/core/res/res/layout/fragment_bread_crumb_item.xml
index 408f6e8..517c570 100644
--- a/core/res/res/layout/fragment_bread_crumb_item.xml
+++ b/core/res/res/layout/fragment_bread_crumb_item.xml
@@ -19,7 +19,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceMediumInverse"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:drawableLeft="@drawable/nav_divider"
android:paddingLeft="12dp"
android:drawablePadding="12dp"
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index 39c88722..57091a1 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -36,7 +36,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textAppearance="?android:attr/textAppearanceLarge"
android:singleLine="true"
android:duplicateParentState="true"
android:ellipsize="marquee"
@@ -48,7 +48,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignParentLeft="true"
- android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
android:duplicateParentState="true" />
diff --git a/core/res/res/values-xlarge/config.xml b/core/res/res/values-xlarge/config.xml
index 7e5a27b..813651e 100644
--- a/core/res/res/values-xlarge/config.xml
+++ b/core/res/res/values-xlarge/config.xml
@@ -25,6 +25,9 @@
<string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.tablet.TabletStatusBarService</string>
<bool name="config_statusBarCanHide">false</bool>
+ <!-- see comment in values/config.xml -->
+ <integer name="config_longPressOnPowerBehavior">2</integer>
+
<!-- Show sliding tab before lockscreen -->
<bool name="config_enableSlidingTabFirst">false</bool>
<!-- Enable lockscreen rotation -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 33d3eeb..d9f0039 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -551,6 +551,10 @@
anchor for positioning the cursor within text. -->
<attr name="textSelectHandle" format="reference" />
+ <!-- Theme to use for dialogs spawned from this theme. -->
+ <attr name="dialogTheme" format="reference" />
+ <!-- Theme to use for alert dialogs spawned from this theme. -->
+ <attr name="alertDialogTheme" format="reference" />
</declare-styleable>
<!-- **************************************************************** -->
@@ -2605,8 +2609,10 @@
<!-- @hide -->
<declare-styleable name="WeightedLinearLayout">
- <attr name="majorWeight" format="float" />
- <attr name="minorWeight" format="float" />
+ <attr name="majorWeightMin" format="float" />
+ <attr name="minorWeightMin" format="float" />
+ <attr name="majorWeightMax" format="float" />
+ <attr name="minorWeightMax" format="float" />
</declare-styleable>
<!-- ========================= -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 71967d4a..f6c5f34 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -221,6 +221,13 @@
closed. The default is 0. -->
<integer name="config_lidNavigationAccessibility">0</integer>
+ <!-- Control the behavior when the user long presses the power button.
+ 0 - Nothing
+ 1 - Global actions menu
+ 2 - Power off (with confirmation)
+ -->
+ <integer name="config_longPressOnPowerBehavior">1</integer>
+
<!-- Indicate whether the SD card is accessible without removing the battery. -->
<bool name="config_batterySdCardAccessibility">false</bool>
@@ -425,6 +432,10 @@
<!-- Enables SIP on WIFI only -->
<bool name="config_sip_wifi_only">false</bool>
+ <!-- Boolean indicating if restoring network selection should be skipped -->
+ <!-- The restoring is handled by modem if it is true-->
+ <bool translatable="false" name="skip_restoring_network_selection">false</bool>
+
<!-- Number of database connections opened and managed by framework layer
to handle queries on each database. -->
<integer name="db_connection_pool_size">1</integer>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2c3c4fc..ae25715 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1366,6 +1366,8 @@
<public type="attr" name="listDividerAlertDialog" />
<public type="attr" name="textColorAlertDialogListItem" />
<public type="attr" name="loopViews" />
+ <public type="attr" name="dialogTheme" />
+ <public type="attr" name="alertDialogTheme" />
<public type="anim" name="animator_fade_in" />
<public type="anim" name="animator_fade_out" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 521a739..0172827 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -280,9 +280,16 @@
<!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
<string name="shutdown_progress">Shutting down\u2026</string>
- <!-- Shutdown Confirmation Dialog. When the user chooses to power off the phone, there will be a confirmation dialog. This is the message. -->
+ <!-- Shutdown Confirmation Dialog. When the user chooses to power off the phone, there will
+ be a confirmation dialog. This is the message. -->
<string name="shutdown_confirm">Your phone will shut down.</string>
+ <!-- Shutdown Confirmation Dialog. When the user chooses to power off the phone, it asks
+ the user if they'd like to shut down. This is the message. This is used instead of
+ shutdown_confirm when the system is configured to use long press to go directly to the
+ power off dialog instead of the global actions menu. -->
+ <string name="shutdown_confirm_question">Would you like to shut down?</string>
+
<!-- Recent Tasks dialog: title
TODO: this should move to SystemUI.apk, but the code for the old
recent dialog is still in the framework
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 0f653f1..8f7ace9 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1091,12 +1091,15 @@
</style>
<style name="TextAppearance.Holo.Widget.PopupMenu" parent="TextAppearance.Widget.PopupMenu">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="TextAppearance.Holo.Widget.PopupMenu.Large" parent="TextAppearance.Widget.PopupMenu.Large">
+ <style name="TextAppearance.Holo.Widget.PopupMenu.Large">
+ <item name="android:textSize">22sp</item>
</style>
- <style name="TextAppearance.Holo.Widget.PopupMenu.Small" parent="TextAppearance.Widget.PopupMenu.Small">
+ <style name="TextAppearance.Holo.Widget.PopupMenu.Small">
+ <item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.Holo.Widget.ActionBar.Title"
@@ -1261,6 +1264,7 @@
</style>
<style name="Widget.Holo.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
+ <item name="android:background">@android:drawable/list_section_header_holo_dark</item>
</style>
<style name="Widget.Holo.TextSelectHandle" parent="Widget.TextSelectHandle">
@@ -1335,7 +1339,15 @@
<style name="Widget.Holo.ProgressBar.Large.Inverse" parent="Widget.ProgressBar.Large.Inverse">
</style>
- <style name="Widget.Holo.SeekBar" parent="Widget.SeekBar">
+ <style name="Widget.Holo.SeekBar">
+ <item name="android:indeterminateOnly">false</item>
+ <item name="android:progressDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item>
+ <item name="android:indeterminateDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item>
+ <item name="android:minHeight">16dip</item>
+ <item name="android:maxHeight">16dip</item>
+ <item name="android:thumb">@android:drawable/scrubber_control_holo</item>
+ <item name="android:thumbOffset">16dip</item>
+ <item name="android:focusable">true</item>
</style>
<style name="Widget.Holo.RatingBar" parent="Widget.RatingBar">
@@ -1357,6 +1369,12 @@
</style>
<style name="Widget.Holo.Spinner" parent="Widget.Spinner.DropDown">
+ <item name="android:dropDownSelector">@android:drawable/list_selector_holo_dark</item>
+ <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
+ <item name="android:popupPromptView">@android:layout/simple_dropdown_hint</item>
</style>
<style name="Widget.Holo.Spinner.DropDown">
@@ -1405,15 +1423,21 @@
</style>
<style name="Widget.Holo.ListPopupWindow" parent="Widget.ListPopupWindow">
+ <item name="android:dropDownSelector">@android:drawable/list_selector_holo_dark</item>
+ <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
</style>
- <style name="Widget.Holo.PopupMenu" parent="Widget.PopupMenu">
+ <style name="Widget.Holo.PopupMenu" parent="Widget.Holo.ListPopupWindow">
</style>
<style name="Widget.Holo.ActionButton" parent="Widget.ActionButton">
</style>
<style name="Widget.Holo.ActionButton.Overflow" parent="Widget.ActionButton.Overflow">
+ <item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_dark</item>
</style>
<style name="Widget.Holo.ActionBarView_TabView" parent="Widget.ActionBarView_TabView">
@@ -1441,6 +1465,7 @@
<style name="Widget.Holo.ActionBar" parent="Widget.ActionBar">
<item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Title</item>
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
+ <item name="android:background">@null</item>
</style>
<!-- Light widget styles -->
@@ -1472,6 +1497,7 @@
</style>
<style name="Widget.Holo.Light.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
+ <item name="android:background">@android:drawable/list_section_header_holo_light</item>
</style>
<style name="Widget.Holo.Light.TextSelectHandle" parent="Widget.TextSelectHandle">
@@ -1546,7 +1572,9 @@
<style name="Widget.Holo.Light.ProgressBar.Large.Inverse" parent="Widget.ProgressBar.Large.Inverse">
</style>
- <style name="Widget.Holo.Light.SeekBar" parent="Widget.SeekBar">
+ <style name="Widget.Holo.Light.SeekBar" parent="Widget.Holo.SeekBar">
+ <item name="android:progressDrawable">@android:drawable/scrubber_progress_horizontal_holo_light</item>
+ <item name="android:indeterminateDrawable">@android:drawable/scrubber_progress_horizontal_holo_light</item>
</style>
<style name="Widget.Holo.Light.RatingBar" parent="Widget.RatingBar">
@@ -1568,6 +1596,12 @@
</style>
<style name="Widget.Holo.Light.Spinner" parent="Widget.Spinner.DropDown">
+ <item name="android:dropDownSelector">@android:drawable/list_selector_holo_light</item>
+ <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_light</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
+ <item name="android:popupPromptView">@android:layout/simple_dropdown_hint</item>
</style>
<style name="Widget.Holo.Light.Spinner.DropDown">
@@ -1616,15 +1650,21 @@
</style>
<style name="Widget.Holo.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
+ <item name="android:dropDownSelector">@android:drawable/list_selector_holo_light</item>
+ <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_light</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
</style>
- <style name="Widget.Holo.Light.PopupMenu" parent="Widget.PopupMenu">
+ <style name="Widget.Holo.Light.PopupMenu" parent="Widget.Holo.Light.ListPopupWindow">
</style>
<style name="Widget.Holo.Light.ActionButton" parent="Widget.ActionButton">
</style>
<style name="Widget.Holo.Light.ActionButton.Overflow" parent="Widget.ActionButton.Overflow">
+ <item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
</style>
<style name="Widget.Holo.Light.ActionBarView_TabView" parent="Widget.ActionBarView_TabView">
@@ -1648,6 +1688,7 @@
<style name="Widget.Holo.Light.ActionBar" parent="Widget.ActionBar">
<item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Title</item>
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
+ <item name="android:background">@null</item>
</style>
<!-- Animation Styles -->
@@ -1664,16 +1705,29 @@
<!-- Dialog styles -->
<style name="AlertDialog.Holo" parent="AlertDialog">
- <item name="fullDark">@android:drawable/dialog_full_holo</item>
- <item name="topDark">@android:drawable/dialog_top_holo</item>
- <item name="centerDark">@android:drawable/dialog_middle_holo</item>
- <item name="bottomDark">@android:drawable/dialog_bottom_holo</item>
- <item name="fullBright">@android:drawable/dialog_full_holo</item>
- <item name="topBright">@android:drawable/dialog_top_holo</item>
- <item name="centerBright">@android:drawable/dialog_middle_holo</item>
- <item name="bottomBright">@android:drawable/dialog_bottom_holo</item>
- <item name="bottomMedium">@android:drawable/dialog_bottom_holo</item>
- <item name="centerMedium">@android:drawable/dialog_middle_holo</item>
+ <item name="fullDark">@android:drawable/dialog_full_holo_dark</item>
+ <item name="topDark">@android:drawable/dialog_top_holo_dark</item>
+ <item name="centerDark">@android:drawable/dialog_middle_holo_dark</item>
+ <item name="bottomDark">@android:drawable/dialog_bottom_holo_dark</item>
+ <item name="fullBright">@android:drawable/dialog_full_holo_dark</item>
+ <item name="topBright">@android:drawable/dialog_top_holo_dark</item>
+ <item name="centerBright">@android:drawable/dialog_middle_holo_dark</item>
+ <item name="bottomBright">@android:drawable/dialog_bottom_holo_dark</item>
+ <item name="bottomMedium">@android:drawable/dialog_bottom_holo_dark</item>
+ <item name="centerMedium">@android:drawable/dialog_middle_holo_dark</item>
+ </style>
+
+ <style name="AlertDialog.Holo.Light">
+ <item name="fullDark">@android:drawable/dialog_full_holo_light</item>
+ <item name="topDark">@android:drawable/dialog_top_holo_light</item>
+ <item name="centerDark">@android:drawable/dialog_middle_holo_light</item>
+ <item name="bottomDark">@android:drawable/dialog_bottom_holo_light</item>
+ <item name="fullBright">@android:drawable/dialog_full_holo_light</item>
+ <item name="topBright">@android:drawable/dialog_top_holo_light</item>
+ <item name="centerBright">@android:drawable/dialog_middle_holo_light</item>
+ <item name="bottomBright">@android:drawable/dialog_bottom_holo_light</item>
+ <item name="bottomMedium">@android:drawable/dialog_bottom_holo_light</item>
+ <item name="centerMedium">@android:drawable/dialog_middle_holo_light</item>
</style>
<!-- Window title -->
@@ -1694,4 +1748,10 @@
<item name="android:textAppearance">@style/TextAppearance.Holo.DialogWindowTitle</item>
</style>
+ <style name="DialogWindowTitle.Holo.Light">
+ <item name="android:maxLines">1</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:textAppearance">@style/TextAppearance.Holo.Light.DialogWindowTitle</item>
+ </style>
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 21d91ba..8daa802 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -137,6 +137,8 @@
<!-- Dialog attributes -->
<item name="alertDialogStyle">@android:style/AlertDialog</item>
+ <item name="dialogTheme">@android:style/Theme.Dialog</item>
+ <item name="alertDialogTheme">@android:style/Theme.Dialog.Alert</item>
<!-- Panel attributes -->
<item name="panelBackground">@android:drawable/menu_background</item>
@@ -156,8 +158,8 @@
<item name="scrollbarTrackVertical">@null</item>
<!-- Text selection handle attributes -->
- <item name="textSelectHandleLeft">@android:drawable/text_select_handle_middle</item>
- <item name="textSelectHandleRight">@android:drawable/text_select_handle_middle</item>
+ <item name="textSelectHandleLeft">@android:drawable/text_select_handle_left</item>
+ <item name="textSelectHandleRight">@android:drawable/text_select_handle_right</item>
<item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
<item name="textSelectHandleWindowStyle">@android:style/Widget.TextSelectHandle</item>
@@ -689,9 +691,9 @@
<item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_dark</item>
<item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_dark</item>
- <item name="listChoiceBackgroundIndicator">@android:drawable/list_selected_background</item>
+ <item name="listChoiceBackgroundIndicator">@android:drawable/list_selector_holo_dark</item>
- <item name="activatedBackgroundIndicator">@android:drawable/activated_background</item>
+ <item name="activatedBackgroundIndicator">@android:drawable/list_selector_activated_holo_dark</item>
<item name="listDividerAlertDialog">@android:drawable/divider_horizontal_holo_dark</item>
@@ -715,7 +717,7 @@
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
<item name="windowIsFloating">false</item>
- <item name="windowContentOverlay">@android:drawable/title_bar_shadow</item>
+ <item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@android:style/WindowTitle.Holo</item>
<item name="windowTitleSize">25dip</item>
@@ -727,6 +729,8 @@
<!-- Dialog attributes -->
<item name="alertDialogStyle">@android:style/AlertDialog.Holo</item>
+ <item name="dialogTheme">@android:style/Theme.Holo.Dialog</item>
+ <item name="alertDialogTheme">@android:style/Theme.Holo.Dialog.Alert</item>
<!-- Panel attributes -->
<item name="panelBackground">@android:drawable/menu_background</item>
@@ -907,15 +911,15 @@
<item name="listPreferredItemHeight">64dip</item>
<!-- @hide -->
<item name="searchResultListItemHeight">58dip</item>
- <item name="listDivider">@drawable/divider_horizontal_holo_dark</item>
+ <item name="listDivider">@drawable/divider_horizontal_holo_light</item>
<item name="listSeparatorTextViewStyle">@android:style/Widget.Holo.Light.TextView.ListSeparator</item>
- <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio</item>
- <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check</item>
+ <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_light</item>
+ <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_light</item>
- <item name="listChoiceBackgroundIndicator">@android:drawable/list_selected_background</item>
+ <item name="listChoiceBackgroundIndicator">@android:drawable/list_selector_holo_light</item>
- <item name="activatedBackgroundIndicator">@android:drawable/activated_background</item>
+ <item name="activatedBackgroundIndicator">@android:drawable/list_selector_activated_holo_light</item>
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
<item name="expandableListPreferredChildPaddingLeft">
@@ -928,7 +932,7 @@
<item name="expandableListPreferredChildIndicatorRight">
?android:attr/expandableListPreferredItemIndicatorRight</item>
- <item name="listDividerAlertDialog">@android:drawable/divider_horizontal_holo_dark</item>
+ <item name="listDividerAlertDialog">@android:drawable/divider_horizontal_holo_light</item>
<!-- Gallery attributes -->
<item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
@@ -939,7 +943,7 @@
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
<item name="windowIsFloating">false</item>
- <item name="windowContentOverlay">@android:drawable/title_bar_shadow</item>
+ <item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@android:style/WindowTitle.Holo</item>
<item name="windowTitleSize">25dip</item>
@@ -950,7 +954,9 @@
<item name="windowActionModeOverlay">false</item>
<!-- Dialog attributes -->
- <item name="alertDialogStyle">@android:style/AlertDialog.Holo</item>
+ <item name="alertDialogStyle">@android:style/AlertDialog.Holo.Light</item>
+ <item name="dialogTheme">@android:style/Theme.Holo.Light.Dialog</item>
+ <item name="alertDialogTheme">@android:style/Theme.Holo.Light.Dialog.Alert</item>
<!-- Panel attributes -->
<item name="panelBackground">@android:drawable/menu_background</item>
@@ -1024,8 +1030,8 @@
<item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.Holo.QuickContactBadgeSmall.WindowSmall</item>
<item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.Holo.QuickContactBadgeSmall.WindowMedium</item>
<item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
- <item name="listPopupWindowStyle">@android:style/Widget.Holo.ListPopupWindow</item>
- <item name="popupMenuStyle">@android:style/Widget.Holo.PopupMenu</item>
+ <item name="listPopupWindowStyle">@android:style/Widget.Holo.Light.ListPopupWindow</item>
+ <item name="popupMenuStyle">@android:style/Widget.Holo.Light.PopupMenu</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
@@ -1101,7 +1107,7 @@
<style name="Theme.Holo.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowTitleStyle">@android:style/DialogWindowTitle.Holo</item>
- <item name="android:windowBackground">@android:drawable/dialog_full_holo</item>
+ <item name="android:windowBackground">@android:drawable/dialog_full_holo_dark</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Holo.Dialog</item>
@@ -1138,4 +1144,40 @@
<item name="windowContentOverlay">@null</item>
</style>
+ <!-- Light holo dialog themes -->
+
+ <!-- Holo light theme for dialog windows and activities, which is used by the
+ {@link android.app.Dialog} class. This changes the window to be
+ floating (not fill the entire screen), and puts a frame around its
+ contents. You can set this theme on an activity if you would like to
+ make an activity that looks like a Dialog.
+ This is the default Dialog theme for applications targeting Honeycomb
+ or newer. -->
+ <style name="Theme.Holo.Light.Dialog">
+ <item name="android:windowFrame">@null</item>
+ <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.Holo.Light</item>
+ <item name="android:windowBackground">@android:drawable/dialog_full_holo_light</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.Holo.Dialog</item>
+ <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
+ <item name="android:windowActionBar">false</item>
+
+ <item name="android:colorBackgroundCacheHint">@null</item>
+
+ <item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
+ <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
+ </style>
+
+ <!-- Holo light theme for alert dialog windows, which is used by the
+ {@link android.app.AlertDialog} class. This is basically a dialog
+ but sets the background to empty so it can do two-tone backgrounds.
+ For applications targeting Honeycomb or newer, this is the default
+ AlertDialog theme. -->
+ <style name="Theme.Holo.Light.Dialog.Alert">
+ <item name="windowBackground">@android:color/transparent</item>
+ <item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo.Light</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
</resources>
diff --git a/core/tests/coretests/res/raw/test1.obb b/core/tests/coretests/res/raw/test1.obb
new file mode 100644
index 0000000..170e36f
--- /dev/null
+++ b/core/tests/coretests/res/raw/test1.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/test1_nosig.obb b/core/tests/coretests/res/raw/test1_nosig.obb
new file mode 100644
index 0000000..5c3573f7
--- /dev/null
+++ b/core/tests/coretests/res/raw/test1_nosig.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/test1_wrongpackage.obb b/core/tests/coretests/res/raw/test1_wrongpackage.obb
new file mode 100644
index 0000000..2e02eaa
--- /dev/null
+++ b/core/tests/coretests/res/raw/test1_wrongpackage.obb
Binary files differ
diff --git a/core/tests/coretests/src/com/android/server/MountServiceTests.java b/core/tests/coretests/src/com/android/server/MountServiceTests.java
new file mode 100644
index 0000000..83e9d18
--- /dev/null
+++ b/core/tests/coretests/src/com/android/server/MountServiceTests.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import com.android.frameworks.coretests.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.storage.OnObbStateChangeListener;
+import android.os.storage.StorageManager;
+import android.test.AndroidTestCase;
+import android.test.ComparisonFailure;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.File;
+import java.io.InputStream;
+
+public class MountServiceTests extends AndroidTestCase {
+ private static final String TAG = "MountServiceTests";
+
+ private static final long MAX_WAIT_TIME = 25*1000;
+ private static final long WAIT_TIME_INCR = 5*1000;
+
+ private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private static void assertStartsWith(String message, String prefix, String actual) {
+ if (!actual.startsWith(prefix)) {
+ throw new ComparisonFailure(message, prefix, actual);
+ }
+ }
+
+ private interface CompletableTask {
+ public boolean isDone();
+ }
+
+ private static class ObbObserver extends OnObbStateChangeListener implements CompletableTask {
+ public String path;
+ public String state;
+ boolean done = false;
+
+ @Override
+ public void onObbStateChange(String path, String state) {
+ synchronized (this) {
+ this.path = path;
+ this.state = state;
+ done = true;
+ notifyAll();
+ }
+ }
+
+ public void reset() {
+ this.path = null;
+ this.state = null;
+ done = false;
+ }
+
+ public boolean isDone() {
+ return done;
+ }
+ }
+
+ private boolean waitForCompletion(CompletableTask task) {
+ long waitTime = 0;
+ synchronized (task) {
+ while (!task.isDone() && waitTime < MAX_WAIT_TIME) {
+ try {
+ task.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ } catch (InterruptedException e) {
+ Log.i(TAG, "Interrupted during sleep", e);
+ }
+ }
+ }
+
+ return task.isDone();
+ }
+ private File getFilePath(String name) {
+ final File filesDir = mContext.getFilesDir();
+ final File outFile = new File(filesDir, name);
+ return outFile;
+ }
+
+ private void copyRawToFile(int rawResId, File outFile) {
+ Resources res = mContext.getResources();
+ InputStream is = null;
+ try {
+ is = res.openRawResource(rawResId);
+ } catch (NotFoundException e) {
+ fail("Failed to load resource with id: " + rawResId);
+ }
+ FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IRWXO, -1, -1);
+ assertTrue(FileUtils.copyToFile(is, outFile));
+ FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IRWXO, -1, -1);
+ }
+
+ private StorageManager getStorageManager() {
+ return (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
+ }
+
+ private void mountObb(StorageManager sm, final int resource, final File file,
+ String expectedState) {
+ copyRawToFile(resource, file);
+
+ ObbObserver observer = new ObbObserver();
+ assertTrue("mountObb call on " + file.getPath() + " should succeed",
+ sm.mountObb(file.getPath(), null, observer));
+
+ assertTrue("Mount should have completed",
+ waitForCompletion(observer));
+
+ assertEquals("Actual file and resolved file should be the same",
+ file.getPath(), observer.path);
+
+ assertEquals(expectedState, observer.state);
+ }
+
+ private String checkMountedPath(StorageManager sm, File file) {
+ final String mountPath = sm.getMountedObbPath(file.getPath());
+ assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX,
+ OBB_MOUNT_PREFIX,
+ mountPath);
+ return mountPath;
+ }
+
+ private void unmountObb(StorageManager sm, final File outFile) {
+ ObbObserver observer = new ObbObserver();
+ assertTrue("unmountObb call on test1.obb should succeed",
+ sm.unmountObb(outFile.getPath(), false, observer));
+
+ assertTrue("Unmount should have completed",
+ waitForCompletion(observer));
+ }
+
+ @LargeTest
+ public void testMountAndUnmountObbNormal() {
+ StorageManager sm = getStorageManager();
+
+ final File outFile = getFilePath("test1.obb");
+
+ mountObb(sm, R.raw.test1, outFile, Environment.MEDIA_MOUNTED);
+
+ final String mountPath = checkMountedPath(sm, outFile);
+ final File mountDir = new File(mountPath);
+
+ assertTrue("OBB mounted path should be a directory",
+ mountDir.isDirectory());
+
+ unmountObb(sm, outFile);
+ }
+
+ @LargeTest
+ public void testAttemptMountNonObb() {
+ StorageManager sm = getStorageManager();
+
+ final File outFile = getFilePath("test1_nosig.obb");
+
+ mountObb(sm, R.raw.test1_nosig, outFile, Environment.MEDIA_BAD_REMOVAL);
+
+ assertFalse("OBB should not be mounted",
+ sm.isObbMounted(outFile.getPath()));
+
+ assertNull("OBB's mounted path should be null",
+ sm.getMountedObbPath(outFile.getPath()));
+ }
+
+ @LargeTest
+ public void testAttemptMountObbWrongPackage() {
+ StorageManager sm = getStorageManager();
+
+ final File outFile = getFilePath("test1_wrongpackage.obb");
+
+ mountObb(sm, R.raw.test1_wrongpackage, outFile, Environment.MEDIA_BAD_REMOVAL);
+
+ assertFalse("OBB should not be mounted",
+ sm.isObbMounted(outFile.getPath()));
+
+ assertNull("OBB's mounted path should be null",
+ sm.getMountedObbPath(outFile.getPath()));
+ }
+}
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 9793748..da8c927 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -278,6 +278,10 @@
</li>
</ul>
</li>
+ <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
+ <span class="en">Device Administration</span></a>
+ <span class="new">new!</span>
+ </li>
</ul>
</li>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
new file mode 100644
index 0000000..4d9a14f
--- /dev/null
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -0,0 +1,494 @@
+page.title=Android Device Administration API
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+<li><a href="#overview">Device Administration API Overview</a>
+ <ol>
+ <li><a href="#policies">Policies</a></li>
+ </ol>
+ </li>
+ <li><a href="#how">How Does It Work?</a></li>
+ <li><a href="#sample">Sample Application</a></li>
+ <li><a href="#developing">Developing a Device Administration Application</a>
+ <ol>
+ <li><a href="#manifest">Creating the Manifest</a></li>
+ <li><a href="#code">Implementing the Code</a>
+ </li>
+ </ol>
+ </ol>
+ </div>
+</div>
+
+<p>Android 2.2 introduces support for enterprise applications by offering the
+Android Device Administration API. The Device Administration API provides device
+administration features at the system level. These APIs allow you to create
+security-aware applications that are useful in enterprise settings, in which IT
+professionals require rich control over employee devices. For example, the
+built-in Android Email application has leveraged the new APIs to improve
+Exchange support. Through the Email application, Exchange administrators can
+enforce password policies — including alphanumeric passwords or numeric
+PINs — across devices. Administrators can also remotely wipe (that is,
+restore factory defaults on) lost or stolen handsets. Exchange users can sync
+their email and calendar data.</p>
+
+<p>This document is intended for developers who want to develop enterprise
+solutions for Android-powered devices. It discusses the various features
+provided by the Device Administration API to provide stronger security for
+employee devices that are powered by Android.</p>
+<h2 id="overview">Device Administration API Overview</h2>
+<p>Here are examples of the types of applications that might use the Device Administration API:</p>
+<ul>
+ <li>Email clients.</li>
+ <li>Security applications that do remote wipe.</li>
+ <li>Device management services and applications.</li>
+</ul>
+
+<h3 id="how">How Does it Work?</h3>
+<p>You use the Device Administration API to write device admin applications that users
+install on their devices. The device admin application enforces the desired
+policies. Here's how it works:</p> <ul>
+ <li>A system administrator writes a device admin application that enforces
+remote/local device security policies. These policies could be hard-coded into
+the app, or the application could dynamically fetch policies from a third-party
+server. </li>
+<li>The application is installed on users' devices. Android does
+not currently have an automated provisioning solution. Some of the ways a sysadmin might
+distribute the application to users are as follows:
+<ul>
+<li>Android Market.</li>
+<li>Enabling non-market installation.</li>
+<li>Distributing the application through other means, such as email or websites.</li>
+
+</ul>
+
+
+</li>
+ <li>The system prompts the user to enable the device admin application. How
+and when this happens depends on how the application is implemented.</li>
+<li>Once users enable the device admin application, they are subject to
+its policies. Complying with those policies typically confers benefits, such as
+access to sensitive systems and data.</li>
+</ul>
+<p>If users do not enable the device admin app, it remains on the device, but in an inactive state. Users will not be subject to its policies, and they will conversely not get any of the application's benefits—for example, they may not be able to sync data.</p>
+<p>If a user fails to comply with the policies (for example, if a user sets a
+password that violates the guidelines), it is up to the application to decide
+how to handle this. However, typically this will result in the user not being
+able to sync data.</p>
+<p>If a device attempts to connect to a server that requires policies not
+supported in the Device Administration API, the connection will not
+be allowed. The Device Administration API does not currently allow partial
+provisioning. In other words, if a device (for example, a legacy device) does
+not support all of the stated policies, there is no way to allow the
+device to connect.</p>
+<p>If a device contains multiple enabled admin applications, the strictest policy is
+enforced. There is no way to target a particular admin
+application.</p>
+<p>To uninstall an existing device admin application, users need to
+first unregister the application as an administrator. </p>
+
+<h3 id ="policies">Policies</h3>
+<p>In an enterprise setting, it's often the case that employee devices must
+adhere to a strict set of policies that govern the use of the device. The
+Device Administration API supports the policies listed in Table 1.
+Note that the Device Administration API currently only supports passwords for screen
+lock:</p>
+<p class="table-caption"><strong>Table 1.</strong> Policies supported by the Device Administration API.</p>
+<table border="1">
+ <tr>
+ <th>Policy</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>Password enabled</td>
+ <td>Requires that devices ask for PIN or passwords.</td>
+ </tr>
+ <tr>
+ <td>Minimum password length</td>
+ <td>Set the required number of characters for the password. For example, you
+can require PIN or passwords to have at least six characters. </td> </tr>
+ <tr>
+ <td>Alphanumeric password required</td>
+ <td>Requires that passwords have a
+combination of letters and numbers. They may include symbolic characters.
+ </td>
+ </tr>
+ <tr>
+ <td>Maximum failed password attempts </td>
+ <td>Specifies how many times a user can enter the wrong password before the
+device wipes its data. The Device Administration API also allows administrators to
+remotely reset the device to factory defaults. This secures data in case the
+device is lost or stolen.</td>
+ </tr>
+ <tr>
+ <td>Maximum inactivity time lock</td>
+ <td>Sets the length of time since the user last touched the screen or
+pressed a button before the device locks the screen. When this happens, users
+need to enter their PIN or passwords again before they can use their devices and
+access data. The value can be between 1 and 60 minutes.</td> </tr>
+</table>
+<h4>Other Features</h4>
+<p>In addition to supporting the policies listed in the above table, the Device
+Administration API lets you do the following:</p> <ul>
+ <li>Prompt user to set a new password.</li>
+ <li>Lock device immediately.</li>
+ <li>Wipe the device's data (that is, restore the device to its factory defaults).</li>
+</ul>
+
+
+<h2 id="sample">Sample Application</h2>
+<p>The examples used in this document are based on the <a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/
+android/apis/app/DeviceAdminSample.html">Device Administration API
+sample</a>, which is included in the SDK samples. For information on downloading and
+installing the SDK samples, see <a
+href="{@docRoot}resources/samples/get.html">
+Getting the Samples</a>. Here is the <a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/
+android/apis/app/DeviceAdminSample.html">complete code</a> for
+the sample. </p>
+<p>The
+sample application offers a demo of device admin features. It presents users
+with a user interface that lets them enable the device admin application. Once
+they've enabled the application, they can use the buttons in the user interface
+to do the following:</p>
+<ul>
+ <li>Set password quality.</li>
+ <li>Specify the minimum length for the user's password.</li>
+ <li>Set the password. If the password does not conform to the specified
+policies, the system returns an error.</li>
+ <li>Set how many failed password attempts can occur before the device is wiped
+(that is, restored to factory settings).</li>
+ <li>Set the maximum amount of inactive time that can elapse before the device
+locks.</li>
+ <li>Make the device lock immediately.</li>
+ <li>Wipe the device's data (that is, restore factory settings).</li>
+</ul>
+
+<img src="{@docRoot}images/admin/device-admin-app.png"/>
+<p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Sample Application</p>
+
+<h2 id="developing">Developing a Device Administration Application</h2>
+
+<p>System administrators can use the Device Administration API to write an application
+that enforces remote/local device security policy enforcement. This section
+summarizes the steps involved in creating a device administration
+application.</p>
+<h3 id="manifest">Creating the Manifest</h3>
+<p>To use the Device Administration API, the application's
+manifest must include the following:</p>
+<ul>
+ <li>A subclass of {@link android.app.admin.DeviceAdminReceiver} that includes the following:
+ <ul>
+ <li>The {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission.</li>
+ <li>The ability to respond to the {@link android.app.admin.DeviceAdminReceiver#ACTION_DEVICE_ADMIN_ENABLED}
+intent, expressed in the manifest as an intent filter.</li>
+ </ul>
+ </li>
+ <li>A declaration of security policies used in metadata.</li>
+</ul>
+<p>Here is an excerpt from the Device Administration sample manifest:</p>
+<pre><activity android:name=".app.DeviceAdminSample$Controller"
+ android:label="@string/activity_sample_device_admin">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+</activity>
+
+<receiver android:name=".app.DeviceAdminSample"
+ android:label="@string/sample_device_admin"
+ android:description="@string/sample_device_admin_description"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_sample" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+</receiver></pre>
+
+ <p>Note that:</p>
+<ul>
+ <li>The activity in the sample application is an {@link android.app.Activity}
+subclass called <code>Controller</code>. The syntax
+<code>".app.DeviceAdminSample$Controller"</code> indicates that
+<code>Controller</code> is an inner class that is nested inside the
+<code>DeviceAdminSample</code> class. Note that an Activity does not need to be
+an inner class; it just is in this example.</li>
+
+<li>The following attributes refer to string resources that for the sample application reside in
+<code>ApiDemos/res/values/strings.xml</code>. For more information about resources, see
+<a
+href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.
+<ul>
+<li><code>android:label="@string/activity_sample_device_admin"</code> refers to the
+user-readable label for the activity.</li>
+
+<li><code>android:label="@string/sample_device_admin"</code> refers to the
+user-readable label for the permission.</li>
+
+<li><code>android:description="@string/sample_device_admin_description"</code> refers to
+the user-readable description of the permission. A descripton is typically longer and more
+informative than
+a label.</li>
+</ul>
+
+
+<li><code>android:permission="android.permission.BIND_DEVICE_ADMIN"
+</code> is a permission that a {@link android.app.admin.DeviceAdminReceiver} subclass must
+have, to ensure that only the system can interact with the receiver (no application can be granted this permission). This
+prevents other applications from abusing your device admin app.</li>
+<li><code>android.app.action.DEVICE_ADMIN_ENABLED</code> is the the primary
+action that a {@link android.app.admin.DeviceAdminReceiver} subclass must handle to be
+allowed to manage a device. This is set to the receiver when the user enables
+the device admin app. Your code typically handles this in
+{@link android.app.admin.DeviceAdminReceiver#onEnabled onEnabled()}. To be supported, the receiver must also
+require the {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission so that other applications
+cannot abuse it. </li>
+<li>When a user enables the device admin application, that gives the receiver
+permission to perform actions in response to the broadcast of particular system
+events. When suitable event arises, the application can impose a policy. For
+example, if the user attempts to set a new password that doesn't meet the policy
+requirements, the application can prompt the user to pick a different password
+that does meet the requirements.</li>
+
+ <li><code>android:resource="@xml/device_admin_sample"</code>
+declares the security policies used in metadata. The metadata provides additional
+information specific to the device administrator, as parsed by the {@link
+android.app.admin.DeviceAdminInfo} class. Here are the contents of
+<code>device_admin_sample.xml</code>:</li>
+</ul>
+<pre><device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-policies>
+ <limit-password />
+ <watch-login />
+ <reset-password />
+ <force-lock />
+ <wipe-data />
+ </uses-policies>
+</device-admin>
+</pre>
+<p> In designing your device administration application, you don't need to
+include all of the policies, just the ones that are relevant for your app.
+</p>
+For more discussion of the manifest file, see the <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android Developers Guide</a>.
+<h2 id="code">Implementing the Code</h2>
+<p>The Device Administration API includes the following classes:</p>
+<dl>
+ <dt>{@link android.app.admin.DeviceAdminReceiver}</dt>
+ <dd>Base class for implementing a device administration component. This class provides
+a convenience for interpreting the raw intent actions that are sent by the
+system. Your Device Administration application must include a
+{@link android.app.admin.DeviceAdminReceiver} subclass.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager}</dt>
+<dd>A class for managing policies enforced on a device. Most clients of
+this class must have published a {@link android.app.admin.DeviceAdminReceiver} that the user
+has currently enabled. The {@link android.app.admin.DevicePolicyManager} manages policies for
+one or more {@link android.app.admin.DeviceAdminReceiver} instances</dd>
+ <dt>{@link android.app.admin.DeviceAdminInfo}</dt>
+<dd>This class is used to specify metadata
+for a device administrator component.</dd>
+</dl>
+<p>These classes provide the foundation for a fully functional device administration application.
+The rest of this section describes how you use the {@link
+android.app.admin.DeviceAdminReceiver} and
+{@link android.app.admin.DevicePolicyManager} APIs to write a device admin application.</p>
+<h4 id="receiver">Subclassing DeviceAdminReceiver</h4>
+<p>To create a device admin application, you must subclass
+{@link android.app.admin.DeviceAdminReceiver}. The {@link android.app.admin.DeviceAdminReceiver} class
+consists of a series of callbacks that are triggered when particular events
+occur.</p>
+<p>In its {@link android.app.admin.DeviceAdminReceiver} subclass, the sample application
+simply displays a {@link android.widget.Toast} notification in response to particular
+events. For example:</p>
+<pre>public class DeviceAdminSample extends DeviceAdminReceiver {
+
+...
+ @Override
+ public void onEnabled(Context context, Intent intent) {
+ showToast(context, "Sample Device Admin: enabled");
+ }
+
+ @Override
+ public CharSequence onDisableRequested(Context context, Intent intent) {
+ return "This is an optional message to warn the user about disabling.";
+ }
+
+ @Override
+ public void onDisabled(Context context, Intent intent) {
+ showToast(context, "Sample Device Admin: disabled");
+ }
+
+ @Override
+ public void onPasswordChanged(Context context, Intent intent) {
+ showToast(context, "Sample Device Admin: pw changed");
+ }
+
+ void showToast(Context context, CharSequence msg) {
+ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
+ }
+...
+}</pre>
+<h4 id="enabling">Enabling the Application</h4>
+<p>One of the major events a device admin application has to handle is the user
+enabling the application. The user must explicitly enable the application for
+the policies to be enforced. If the user chooses not to enable the application
+it will still be present on the device, but its policies will not be enforced, and the user will not
+get any of the application's benefits.</p>
+<p>The process of enabling the application begins when the user performs an
+action that triggers the {@link android.app.admin.DevicePolicyManager#ACTION_ADD_DEVICE_ADMIN}
+intent. In the
+sample application, this happens when the user clicks the <strong>Enable
+Admin</strong> button. </p>
+<p>When the user clicks the <strong>Enable Admin</strong> button, the display
+changes to prompt the user to enable the device admin application, as shown in <strong>Figure 2</strong>.</p>
+
+<img src="{@docRoot}images/admin/device-admin-activate-prompt.png"/>
+<p class="img-caption"><strong>Figure 2.</strong> Sample Application: Activating the Application</p>
+<p>Below is the code that gets executed when the user clicks the <strong>Enable
+Admin</strong> button shown in <strong>Figure 1</strong>. </p>
+
+<pre> private OnClickListener mEnableListener = new OnClickListener() {
+ public void onClick(View v) {
+ // Launch the activity to have the user enable our admin.
+ Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
+ intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+ mDeviceAdminSample);
+ intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
+ "Additional text explaining why this needs to be added.");
+ startActivityForResult(intent, RESULT_ENABLE);
+ }
+};
+
+...
+// This code checks whether the device admin app was successfully enabled.
+@Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case RESULT_ENABLE:
+ if (resultCode == Activity.RESULT_OK) {
+ Log.i("DeviceAdminSample", "Administration enabled!");
+ } else {
+ Log.i("DeviceAdminSample", "Administration enable FAILED!");
+ }
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+}</pre>
+
+<p>The line
+<code>intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+mDeviceAdminSample)</code> states that <code>mDeviceAdminSample</code> (which is
+a {@link android.app.admin.DeviceAdminReceiver} component) is the target policy.
+This line invokes the user interface shown in <strong>Figure 2</strong>, which guides users through
+adding the device administrator to the system (or allows them to reject it).</p>
+
+<p>When the application needs to perform an operation that is contingent on the
+device admin application being enabled, it confirms that the application is
+active. To do this it uses the {@link android.app.admin.DevicePolicyManager} method
+{@link android.app.admin.DevicePolicyManager#isAdminActive(android.content.ComponentName) isAdminActive()}. Notice that the {@link android.app.admin.DevicePolicyManager}
+method {@link android.app.admin.DevicePolicyManager#isAdminActive(android.content.ComponentName) isAdminActive()} takes a {@link android.app.admin.DeviceAdminReceiver}
+component as its argument:</p>
+<pre>
+DevicePolicyManager mDPM;
+...
+boolean active = mDPM.isAdminActive(mDeviceAdminSample);
+if (active) {
+ // Admin app is active, so do some admin stuff
+ ...
+} else {
+ // do something else
+}
+</pre>
+<h3 id="admin_ops">Managing Policies</h3>
+<p>{@link android.app.admin.DevicePolicyManager} is a public class for managing policies
+enforced on a device. {@link android.app.admin.DevicePolicyManager} manages policies for one
+or more {@link android.app.admin.DeviceAdminReceiver} instances. </p>
+<p>You get a handle to the {@link android.app.admin.DevicePolicyManager} as follows: </p>
+<pre>DevicePolicyManager mDPM =
+(DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);<br
+/></pre>
+<p>This section describes how to use {@link android.app.admin.DevicePolicyManager} to perform
+ administrative tasks:</p>
+<ul>
+ <li><a href="#pwd">Set password policies</a></li>
+ <li><a href="#lock">Set device lock</a></li>
+ <li><a href="#wipe">Perform data wipe</a></li>
+</ul>
+<h4 id="pwd">Set password policies</h4>
+<p>{@link android.app.admin.DevicePolicyManager} includes APIs for setting and enforcing the
+device password policy. In the Device Administration API, the password only applies to
+screen lock. This section describes common password-related tasks.</p>
+<h5>Set a password for the device</h5>
+<p>This code displays a user interface prompting the user to set a password:</p>
+<pre>Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+startActivity(intent);
+</pre>
+<h5>Set the password quality</h5>
+<p>The password quality can be one of the following {@link android.app.admin.DevicePolicyManager} constants: </p>
+<dl>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHABETIC}</dt><dd>The user must enter a
+password containing at least alphabetic (or other symbol) characters.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHANUMERIC}</dt><dd>The user must enter a
+password containing at least <em>both</em> numeric <em>and</em> alphabetic (or
+other symbol) characters.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_NUMERIC}</dt><dd>The user must enter a password
+containing at least numeric characters.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
+of password, but doesn't care what it is.</dd>
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}</dt><dd>
+ The policy has no requirements for the password. </dd>
+</dl>
+<p>For example, this is how you would set the password policy to require an alphanumeric password:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
+</pre>
+<h5>Set the minimum password length</h5>
+<p>You can specify that a password must be at least the specified minimum
+length. For example:</p>
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwLength;
+...
+mDPM.setPasswordMinimumLength(mDeviceAdminSample, pwLength);
+</pre>
+<h5>Set maximum failed password attempts</h5>
+<p>You can set the maximum number of allowed failed password attempts before the
+device is wiped (that is, reset to factory settings). For example:</p>
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int maxFailedPw;
+ ...
+mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);</pre>
+<h4 id="lock">Set device lock</h4>
+<p>You can set the maximum period of user inactivity that can occur before the
+device locks. For example:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+long timeMs = 1000L*Long.parseLong(mTimeout.getText().toString());
+mDPM.setMaximumTimeToLock(mDeviceAdminSample, timeMs);
+</pre>
+<p>You can also programmatically tell the device to lock immediately:</p>
+<pre>
+DevicePolicyManager mDPM;
+mDPM.lockNow();</pre>
+<h4 id="wipe">Perform data wipe</h4>
+<p>You can use the {@link android.app.admin.DevicePolicyManager} method
+{@link android.app.admin.DevicePolicyManager#wipeData wipeData()} to reset the device to factory settings. This is useful
+if the device is lost or stolen. Often the decision to wipe the device is the
+result of certain conditions being met. For example, you can use
+{@link android.app.admin.DevicePolicyManager#setMaximumFailedPasswordsForWipe setMaximumFailedPasswordsForWipe()} to state that a device should be
+wiped after a specific number of failed password attempts.</p>
+<p>You wipe data as follows:</p>
+<pre>
+DevicePolicyManager mDPM;
+mDPM.wipeData(0);</pre>
+<p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
+additional options. Currently the value must be 0. </p>
diff --git a/docs/html/images/admin/device-admin-activate-prompt.png b/docs/html/images/admin/device-admin-activate-prompt.png
new file mode 100755
index 0000000..fd001bd
--- /dev/null
+++ b/docs/html/images/admin/device-admin-activate-prompt.png
Binary files differ
diff --git a/docs/html/images/admin/device-admin-app.png b/docs/html/images/admin/device-admin-app.png
new file mode 100755
index 0000000..d966a28
--- /dev/null
+++ b/docs/html/images/admin/device-admin-app.png
Binary files differ
diff --git a/drm/common/DrmConstraints.cpp b/drm/common/DrmConstraints.cpp
index 11ce410..4a4d798 100644
--- a/drm/common/DrmConstraints.cpp
+++ b/drm/common/DrmConstraints.cpp
@@ -75,12 +75,10 @@
DrmConstraints::KeyIterator::KeyIterator(const DrmConstraints::KeyIterator& keyIterator)
: mDrmConstraints(keyIterator.mDrmConstraints),
mIndex(keyIterator.mIndex) {
- LOGV("DrmConstraints::KeyIterator::KeyIterator");
}
DrmConstraints::KeyIterator& DrmConstraints::KeyIterator::operator=(
const DrmConstraints::KeyIterator& keyIterator) {
- LOGV("DrmConstraints::KeyIterator::operator=");
mDrmConstraints = keyIterator.mDrmConstraints;
mIndex = keyIterator.mIndex;
return *this;
@@ -94,12 +92,10 @@
DrmConstraints::Iterator::Iterator(const DrmConstraints::Iterator& iterator) :
mDrmConstraints(iterator.mDrmConstraints),
mIndex(iterator.mIndex) {
- LOGV("DrmConstraints::Iterator::Iterator");
}
DrmConstraints::Iterator& DrmConstraints::Iterator::operator=(
const DrmConstraints::Iterator& iterator) {
- LOGV("DrmConstraints::Iterator::operator=");
mDrmConstraints = iterator.mDrmConstraints;
mIndex = iterator.mIndex;
return *this;
diff --git a/drm/common/DrmEngineBase.cpp b/drm/common/DrmEngineBase.cpp
index 70398e8..17cdf544 100644
--- a/drm/common/DrmEngineBase.cpp
+++ b/drm/common/DrmEngineBase.cpp
@@ -52,7 +52,7 @@
return onProcessDrmInfo(uniqueId, drmInfo);
}
-void DrmEngineBase::saveRights(
+status_t DrmEngineBase::saveRights(
int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
return onSaveRights(uniqueId, drmRights, rightsPath, contentPath);
@@ -74,14 +74,14 @@
return onCheckRightsStatus(uniqueId, path, action);
}
-void DrmEngineBase::consumeRights(
+status_t DrmEngineBase::consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
- onConsumeRights(uniqueId, decryptHandle, action, reserve);
+ return onConsumeRights(uniqueId, decryptHandle, action, reserve);
}
-void DrmEngineBase::setPlaybackStatus(
+status_t DrmEngineBase::setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
- onSetPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+ return onSetPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
}
bool DrmEngineBase::validateAction(
@@ -90,16 +90,16 @@
return onValidateAction(uniqueId, path, action, description);
}
-void DrmEngineBase::removeRights(int uniqueId, const String8& path) {
- onRemoveRights(uniqueId, path);
+status_t DrmEngineBase::removeRights(int uniqueId, const String8& path) {
+ return onRemoveRights(uniqueId, path);
}
-void DrmEngineBase::removeAllRights(int uniqueId) {
- onRemoveAllRights(uniqueId);
+status_t DrmEngineBase::removeAllRights(int uniqueId) {
+ return onRemoveAllRights(uniqueId);
}
-void DrmEngineBase::openConvertSession(int uniqueId, int convertId) {
- onOpenConvertSession(uniqueId, convertId);
+status_t DrmEngineBase::openConvertSession(int uniqueId, int convertId) {
+ return onOpenConvertSession(uniqueId, convertId);
}
DrmConvertedStatus* DrmEngineBase::convertData(
@@ -120,24 +120,24 @@
return onOpenDecryptSession(uniqueId, decryptHandle, fd, offset, length);
}
-void DrmEngineBase::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
- onCloseDecryptSession(uniqueId, decryptHandle);
+status_t DrmEngineBase::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+ return onCloseDecryptSession(uniqueId, decryptHandle);
}
-void DrmEngineBase::initializeDecryptUnit(
+status_t DrmEngineBase::initializeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
- onInitializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
+ return onInitializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
}
status_t DrmEngineBase::decrypt(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
- const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
- return onDecrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+ return onDecrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
}
-void DrmEngineBase::finalizeDecryptUnit(
+status_t DrmEngineBase::finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
- onFinalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+ return onFinalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
}
ssize_t DrmEngineBase::pread(
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
index eb58129..8d115a8 100644
--- a/drm/common/DrmInfoEvent.cpp
+++ b/drm/common/DrmInfoEvent.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
-#define LOG_TAG "DrmInfoEvent"
-#include "utils/Log.h"
-
#include <utils/String8.h>
#include <drm/DrmInfoEvent.h>
diff --git a/drm/common/DrmRights.cpp b/drm/common/DrmRights.cpp
index dc1e6c5..3aecb3d 100644
--- a/drm/common/DrmRights.cpp
+++ b/drm/common/DrmRights.cpp
@@ -15,14 +15,21 @@
*/
#include <drm/DrmRights.h>
+#include <ReadWriteUtils.h>
using namespace android;
DrmRights::DrmRights(const String8& rightsFilePath, const String8& mimeType,
- const String8& accountId, const String8& subscriptionId) {
- /**
- * TODO Read DrmRights from rights file
- */
+ const String8& accountId, const String8& subscriptionId) :
+ mMimeType(mimeType),
+ mAccountId(accountId),
+ mSubscriptionId(subscriptionId),
+ mRightsFromFile(NULL) {
+ int rightsLength = 0;
+ if (String8("") != rightsFilePath) {
+ rightsLength = ReadWriteUtils::readBytes(rightsFilePath, &mRightsFromFile);
+ }
+ mData = DrmBuffer(mRightsFromFile, rightsLength);
}
DrmRights::DrmRights(const DrmBuffer& rightsData, const String8& mimeType,
@@ -30,7 +37,12 @@
mData(rightsData),
mMimeType(mimeType),
mAccountId(accountId),
- mSubscriptionId(subscriptionId) {
+ mSubscriptionId(subscriptionId),
+ mRightsFromFile(NULL) {
+}
+
+DrmRights::~DrmRights() {
+ delete[] mRightsFromFile; mRightsFromFile = NULL;
}
const DrmBuffer& DrmRights::getData(void) const {
diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp
index 35e83fc..ffc8953 100644
--- a/drm/common/DrmSupportInfo.cpp
+++ b/drm/common/DrmSupportInfo.cpp
@@ -42,7 +42,7 @@
}
bool DrmSupportInfo::isSupportedMimeType(const String8& mimeType) const {
- for (int i = 0; i < mMimeTypeVector.size(); i++) {
+ for (unsigned int i = 0; i < mMimeTypeVector.size(); i++) {
const String8 item = mMimeTypeVector.itemAt(i);
if (String8("") != mimeType && item.find(mimeType) != -1) {
@@ -53,7 +53,7 @@
}
bool DrmSupportInfo::isSupportedFileSuffix(const String8& fileType) const {
- for (int i = 0; i < mFileSuffixVector.size(); i++) {
+ for (unsigned int i = 0; i < mFileSuffixVector.size(); i++) {
const String8 item = mFileSuffixVector.itemAt(i);
if (String8("") != fileType && item.find(fileType) != -1) {
diff --git a/drm/common/IDrmIOService.cpp b/drm/common/IDrmIOService.cpp
index 7ce45e7..e44ca55 100644
--- a/drm/common/IDrmIOService.cpp
+++ b/drm/common/IDrmIOService.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
-#define LOG_TAG "IDrmIOService"
-#include <utils/Log.h>
-
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index 4fc828a..c28527c 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "IDrmManagerService(Native)"
#include <utils/Log.h>
@@ -36,6 +36,23 @@
using namespace android;
+int BpDrmManagerService::addUniqueId(int uniqueId) {
+ LOGV("add uniqueid");
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+ data.writeInt32(uniqueId);
+ remote()->transact(ADD_UNIQUEID, data, &reply);
+ return reply.readInt32();
+}
+
+void BpDrmManagerService::removeUniqueId(int uniqueId) {
+ LOGV("remove uniqueid");
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+ data.writeInt32(uniqueId);
+ remote()->transact(REMOVE_UNIQUEID, data, &reply);
+}
+
status_t BpDrmManagerService::loadPlugIns(int uniqueId) {
LOGV("load plugins");
Parcel data, reply;
@@ -237,7 +254,7 @@
return drmInfo;
}
-void BpDrmManagerService::saveRights(
+status_t BpDrmManagerService::saveRights(
int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
LOGV("Save Rights");
@@ -264,6 +281,7 @@
data.writeString8((contentPath == String8("")) ? String8("NULL") : contentPath);
remote()->transact(SAVE_RIGHTS, data, &reply);
+ return reply.readInt32();
}
String8 BpDrmManagerService::getOriginalMimeType(int uniqueId, const String8& path) {
@@ -307,10 +325,10 @@
return reply.readInt32();
}
-void BpDrmManagerService::consumeRights(
+status_t BpDrmManagerService::consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
LOGV("consumeRights");
- Parcel data, reply;
+ Parcel data, reply;
data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
data.writeInt32(uniqueId);
@@ -330,9 +348,10 @@
data.writeInt32(static_cast< int>(reserve));
remote()->transact(CONSUME_RIGHTS, data, &reply);
+ return reply.readInt32();
}
-void BpDrmManagerService::setPlaybackStatus(
+status_t BpDrmManagerService::setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
LOGV("setPlaybackStatus");
Parcel data, reply;
@@ -355,6 +374,7 @@
data.writeInt32(position);
remote()->transact(SET_PLAYBACK_STATUS, data, &reply);
+ return reply.readInt32();
}
bool BpDrmManagerService::validateAction(
@@ -375,7 +395,7 @@
return static_cast<bool>(reply.readInt32());
}
-void BpDrmManagerService::removeRights(int uniqueId, const String8& path) {
+status_t BpDrmManagerService::removeRights(int uniqueId, const String8& path) {
LOGV("removeRights");
Parcel data, reply;
@@ -384,9 +404,10 @@
data.writeString8(path);
remote()->transact(REMOVE_RIGHTS, data, &reply);
+ return reply.readInt32();
}
-void BpDrmManagerService::removeAllRights(int uniqueId) {
+status_t BpDrmManagerService::removeAllRights(int uniqueId) {
LOGV("removeAllRights");
Parcel data, reply;
@@ -394,6 +415,7 @@
data.writeInt32(uniqueId);
remote()->transact(REMOVE_ALL_RIGHTS, data, &reply);
+ return reply.readInt32();
}
int BpDrmManagerService::openConvertSession(int uniqueId, const String8& mimeType) {
@@ -517,15 +539,12 @@
Parcel data, reply;
const String16 interfaceDescriptor = IDrmManagerService::getInterfaceDescriptor();
- LOGV("BpDrmManagerService::openDecryptSession: InterfaceDescriptor name is %s",
- interfaceDescriptor.string());
data.writeInterfaceToken(interfaceDescriptor);
data.writeInt32(uniqueId);
data.writeFileDescriptor(fd);
data.writeInt32(offset);
data.writeInt32(length);
- LOGV("try to invoke remote onTransact() with code OPEN_DECRYPT_SESSION");
remote()->transact(OPEN_DECRYPT_SESSION, data, &reply);
DecryptHandle* handle = NULL;
@@ -546,7 +565,7 @@
return handle;
}
-void BpDrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t BpDrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
LOGV("closeDecryptSession");
Parcel data, reply;
@@ -571,9 +590,10 @@
delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL;
}
delete decryptHandle; decryptHandle = NULL;
+ return reply.readInt32();
}
-void BpDrmManagerService::initializeDecryptUnit(
+status_t BpDrmManagerService::initializeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
LOGV("initializeDecryptUnit");
@@ -598,11 +618,12 @@
data.write(headerInfo->data, headerInfo->length);
remote()->transact(INITIALIZE_DECRYPT_UNIT, data, &reply);
+ return reply.readInt32();
}
status_t BpDrmManagerService::decrypt(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
- const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
LOGV("decrypt");
Parcel data, reply;
@@ -626,6 +647,11 @@
data.writeInt32(encBuffer->length);
data.write(encBuffer->data, encBuffer->length);
+ if (NULL != IV) {
+ data.writeInt32(IV->length);
+ data.write(IV->data, IV->length);
+ }
+
remote()->transact(DECRYPT, data, &reply);
const status_t status = reply.readInt32();
@@ -638,7 +664,7 @@
return status;
}
-void BpDrmManagerService::finalizeDecryptUnit(
+status_t BpDrmManagerService::finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
LOGV("finalizeDecryptUnit");
Parcel data, reply;
@@ -660,6 +686,7 @@
data.writeInt32(decryptUnitId);
remote()->transact(FINALIZE_DECRYPT_UNIT, data, &reply);
+ return reply.readInt32();
}
ssize_t BpDrmManagerService::pread(
@@ -702,6 +729,23 @@
LOGV("Entering BnDrmManagerService::onTransact with code %d", code);
switch (code) {
+ case ADD_UNIQUEID:
+ {
+ LOGV("BnDrmManagerService::onTransact :ADD_UNIQUEID");
+ CHECK_INTERFACE(IDrmManagerService, data, reply);
+ int uniqueId = addUniqueId(data.readInt32());
+ reply->writeInt32(uniqueId);
+ return DRM_NO_ERROR;
+ }
+
+ case REMOVE_UNIQUEID:
+ {
+ LOGV("BnDrmManagerService::onTransact :REMOVE_UNIQUEID");
+ CHECK_INTERFACE(IDrmManagerService, data, reply);
+ removeUniqueId(data.readInt32());
+ return DRM_NO_ERROR;
+ }
+
case LOAD_PLUGINS:
{
LOGV("BnDrmManagerService::onTransact :LOAD_PLUGINS");
@@ -711,7 +755,6 @@
reply->writeInt32(status);
return DRM_NO_ERROR;
-
}
case LOAD_PLUGINS_FROM_PATH:
@@ -745,7 +788,8 @@
LOGV("BnDrmManagerService::onTransact :UNLOAD_PLUGINS");
CHECK_INTERFACE(IDrmManagerService, data, reply);
- status_t status = unloadPlugIns(data.readInt32());
+ const int uniqueId = data.readInt32();
+ status_t status = unloadPlugIns(uniqueId);
reply->writeInt32(status);
return DRM_NO_ERROR;
@@ -923,10 +967,11 @@
((accountId == String8("NULL")) ? String8("") : accountId),
((subscriptionId == String8("NULL")) ? String8("") : subscriptionId));
- saveRights(uniqueId, drmRights,
+ const status_t status = saveRights(uniqueId, drmRights,
((rightsPath == String8("NULL")) ? String8("") : rightsPath),
((contentPath == String8("NULL")) ? String8("") : contentPath));
+ reply->writeInt32(status);
return DRM_NO_ERROR;
}
@@ -985,7 +1030,10 @@
handle.decryptInfo->decryptBufferLength = bufferLength;
}
- consumeRights(uniqueId, &handle, data.readInt32(), static_cast<bool>(data.readInt32()));
+ const status_t status
+ = consumeRights(uniqueId, &handle, data.readInt32(),
+ static_cast<bool>(data.readInt32()));
+ reply->writeInt32(status);
delete handle.decryptInfo; handle.decryptInfo = NULL;
return DRM_NO_ERROR;
@@ -1011,7 +1059,9 @@
handle.decryptInfo->decryptBufferLength = bufferLength;
}
- setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
+ const status_t status
+ = setPlaybackStatus(uniqueId, &handle, data.readInt32(), data.readInt32());
+ reply->writeInt32(status);
delete handle.decryptInfo; handle.decryptInfo = NULL;
return DRM_NO_ERROR;
@@ -1037,7 +1087,8 @@
LOGV("BnDrmManagerService::onTransact :REMOVE_RIGHTS");
CHECK_INTERFACE(IDrmManagerService, data, reply);
- removeRights(data.readInt32(), data.readString8());
+ const status_t status = removeRights(data.readInt32(), data.readString8());
+ reply->writeInt32(status);
return DRM_NO_ERROR;
}
@@ -1047,7 +1098,8 @@
LOGV("BnDrmManagerService::onTransact :REMOVE_ALL_RIGHTS");
CHECK_INTERFACE(IDrmManagerService, data, reply);
- removeAllRights(data.readInt32());
+ const status_t status = removeAllRights(data.readInt32());
+ reply->writeInt32(status);
return DRM_NO_ERROR;
}
@@ -1207,7 +1259,8 @@
handle->decryptInfo->decryptBufferLength = bufferLength;
}
- closeDecryptSession(uniqueId, handle);
+ const status_t status = closeDecryptSession(uniqueId, handle);
+ reply->writeInt32(status);
return DRM_NO_ERROR;
}
@@ -1237,7 +1290,9 @@
DrmBuffer* headerInfo = NULL;
headerInfo = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);
- initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
+ const status_t status
+ = initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
+ reply->writeInt32(status);
delete handle.decryptInfo; handle.decryptInfo = NULL;
delete headerInfo; headerInfo = NULL;
@@ -1274,7 +1329,14 @@
buffer = new char[decBufferSize];
DrmBuffer* decBuffer = new DrmBuffer(buffer, decBufferSize);
- const status_t status = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer);
+ DrmBuffer* IV = NULL;
+ if (0 != data.dataAvail()) {
+ const int ivBufferlength = data.readInt32();
+ IV = new DrmBuffer((char *)data.readInplace(ivBufferlength), ivBufferlength);
+ }
+
+ const status_t status
+ = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer, IV);
reply->writeInt32(status);
@@ -1286,6 +1348,7 @@
delete encBuffer; encBuffer = NULL;
delete decBuffer; decBuffer = NULL;
delete [] buffer; buffer = NULL;
+ delete IV; IV = NULL;
return DRM_NO_ERROR;
}
@@ -1309,7 +1372,8 @@
handle.decryptInfo->decryptBufferLength = bufferLength;
}
- finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
+ const status_t status = finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
+ reply->writeInt32(status);
delete handle.decryptInfo; handle.decryptInfo = NULL;
return DRM_NO_ERROR;
diff --git a/drm/common/IDrmServiceListener.cpp b/drm/common/IDrmServiceListener.cpp
index 0a69115..6eeea40 100644
--- a/drm/common/IDrmServiceListener.cpp
+++ b/drm/common/IDrmServiceListener.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
-#define LOG_TAG "IDrmServiceListener"
-#include <utils/Log.h>
-
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
diff --git a/drm/common/ReadWriteUtils.cpp b/drm/common/ReadWriteUtils.cpp
index 4319c1c..7ec4fa2 100644
--- a/drm/common/ReadWriteUtils.cpp
+++ b/drm/common/ReadWriteUtils.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ReadWriteUtils"
+#include <utils/Log.h>
+
#include <ReadWriteUtils.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -22,7 +26,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <utils/FileMap.h>
#include <utils/String8.h>
using namespace android;
@@ -39,18 +42,39 @@
struct stat sb;
if (fstat(fd, &sb) == 0 && sb.st_size > 0) {
- FileMap* fileMap = new FileMap();
- if (fileMap->create(filePath.string(), fd, 0, sb.st_size, true)) {
- char* addr = (char*)fileMap->getDataPtr();
- string.append(addr, sb.st_size);
- fileMap->release();
+ int length = sb.st_size;
+ char* bytes = new char[length];
+ if (length == read(fd, (void*) bytes, length)) {
+ string.append(bytes, length);
}
+ delete bytes;
}
fclose(file);
}
return string;
}
+int ReadWriteUtils::readBytes(const String8& filePath, char** buffer) {
+ FILE* file = NULL;
+ file = fopen(filePath.string(), "r");
+ int length = 0;
+
+ if (NULL != file) {
+ int fd = fileno(file);
+ struct stat sb;
+
+ if (fstat(fd, &sb) == 0 && sb.st_size > 0) {
+ length = sb.st_size;
+ *buffer = new char[length];
+ if (length != read(fd, (void*) *buffer, length)) {
+ length = FAILURE;
+ }
+ }
+ fclose(file);
+ }
+ return length;
+}
+
void ReadWriteUtils::writeToFile(const String8& filePath, const String8& data) {
FILE* file = NULL;
file = fopen(filePath.string(), "w+");
@@ -60,12 +84,8 @@
int size = data.size();
if (FAILURE != ftruncate(fd, size)) {
- FileMap* fileMap = NULL;
- fileMap = new FileMap();
- if (fileMap->create(filePath.string(), fd, 0, size, false)) {
- char* addr = (char*)fileMap->getDataPtr();
- memcpy(addr, data.string(), size);
- fileMap->release();
+ if (size != write(fd, data.string(), size)) {
+ LOGE("Failed to write the data to: %s", filePath.string());
}
}
fclose(file);
@@ -79,20 +99,9 @@
if (NULL != file) {
int fd = fileno(file);
- int offset = lseek(fd, 0, SEEK_END);
- if (FAILURE != offset) {
- int newEntrySize = data.size();
- int fileSize = offset + newEntrySize;
-
- if (FAILURE != ftruncate(fd, fileSize)) {
- FileMap* fileMap = NULL;
- fileMap = new FileMap();
- if (fileMap->create(filePath.string(), fd, offset, fileSize, false)) {
- char* addr = (char*)fileMap->getDataPtr();
- memcpy(addr, data.string(), data.size());
- fileMap->release();
- }
- }
+ int size = data.size();
+ if (size != write(fd, data.string(), size)) {
+ LOGE("Failed to write the data to: %s", filePath.string());
}
fclose(file);
}
diff --git a/drm/drmioserver/DrmIOService.cpp b/drm/drmioserver/DrmIOService.cpp
index 67cfd39..60e6e70 100644
--- a/drm/drmioserver/DrmIOService.cpp
+++ b/drm/drmioserver/DrmIOService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "DrmIOService"
#include <utils/Log.h>
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 44886f9..52527dc 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "DrmManager(Native)"
#include "utils/Log.h"
@@ -36,6 +36,7 @@
using namespace android;
+Vector<int> DrmManager::mUniqueIdVector;
const String8 DrmManager::EMPTY_STRING("");
DrmManager::DrmManager() :
@@ -48,6 +49,42 @@
}
+int DrmManager::addUniqueId(int uniqueId) {
+ if (0 == uniqueId) {
+ int temp = 0;
+ bool foundUniqueId = false;
+ srand(time(NULL));
+
+ while (!foundUniqueId) {
+ const int size = mUniqueIdVector.size();
+ temp = rand() % 100;
+
+ int index = 0;
+ for (; index < size; ++index) {
+ if (mUniqueIdVector.itemAt(index) == temp) {
+ foundUniqueId = false;
+ break;
+ }
+ }
+ if (index == size) {
+ foundUniqueId = true;
+ }
+ }
+ uniqueId = temp;
+ }
+ mUniqueIdVector.push(uniqueId);
+ return uniqueId;
+}
+
+void DrmManager::removeUniqueId(int uniqueId) {
+ for (unsigned int i = 0; i < mUniqueIdVector.size(); i++) {
+ if (uniqueId == mUniqueIdVector.itemAt(i)) {
+ mUniqueIdVector.removeAt(i);
+ break;
+ }
+ }
+}
+
status_t DrmManager::loadPlugIns(int uniqueId) {
String8 pluginDirPath("/system/lib/drm/plugins/native");
return loadPlugIns(uniqueId, pluginDirPath);
@@ -82,10 +119,12 @@
rDrmEngine.terminate(uniqueId);
}
- mConvertSessionMap.clear();
- mDecryptSessionMap.clear();
- mSupportInfoToPlugInIdMap.clear();
- mPlugInManager.unloadPlugIns();
+ if (0 >= mUniqueIdVector.size()) {
+ mConvertSessionMap.clear();
+ mDecryptSessionMap.clear();
+ mSupportInfoToPlugInIdMap.clear();
+ mPlugInManager.unloadPlugIns();
+ }
return DRM_NO_ERROR;
}
@@ -159,13 +198,15 @@
return NULL;
}
-void DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
+status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
+ status_t result = DRM_ERROR_UNKNOWN;
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
+ result = rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
}
+ return result;
}
String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path) {
@@ -195,21 +236,24 @@
return RightsStatus::RIGHTS_INVALID;
}
-void DrmManager::consumeRights(
+status_t DrmManager::consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
- drmEngine->consumeRights(uniqueId, decryptHandle, action, reserve);
+ result = drmEngine->consumeRights(uniqueId, decryptHandle, action, reserve);
}
+ return result;
}
-void DrmManager::setPlaybackStatus(
+status_t DrmManager::setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
-
+ status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
- drmEngine->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+ result = drmEngine->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
}
+ return result;
}
bool DrmManager::validateAction(
@@ -222,21 +266,27 @@
return false;
}
-void DrmManager::removeRights(int uniqueId, const String8& path) {
+status_t DrmManager::removeRights(int uniqueId, const String8& path) {
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
+ status_t result = DRM_ERROR_UNKNOWN;
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- rDrmEngine.removeRights(uniqueId, path);
+ result = rDrmEngine.removeRights(uniqueId, path);
}
+ return result;
}
-void DrmManager::removeAllRights(int uniqueId) {
+status_t DrmManager::removeAllRights(int uniqueId) {
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
-
+ status_t result = DRM_ERROR_UNKNOWN;
for (unsigned int index = 0; index < plugInIdList.size(); index++) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
- rDrmEngine.removeAllRights(uniqueId);
+ result = rDrmEngine.removeAllRights(uniqueId);
+ if (DRM_NO_ERROR != result) {
+ break;
+ }
}
+ return result;
}
int DrmManager::openConvertSession(int uniqueId, const String8& mimeType) {
@@ -246,12 +296,12 @@
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
- Mutex::Autolock _l(mConvertLock);
- ++mConvertId;
- convertId = mConvertId;
- mConvertSessionMap.add(mConvertId, &rDrmEngine);
-
- rDrmEngine.openConvertSession(uniqueId, mConvertId);
+ if (DRM_NO_ERROR == rDrmEngine.openConvertSession(uniqueId, mConvertId + 1)) {
+ Mutex::Autolock _l(mConvertLock);
+ ++mConvertId;
+ convertId = mConvertId;
+ mConvertSessionMap.add(convertId, &rDrmEngine);
+ }
}
return convertId;
}
@@ -310,7 +360,6 @@
}
DecryptHandle* DrmManager::openDecryptSession(int uniqueId, int fd, int offset, int length) {
- LOGV("Entering DrmManager::openDecryptSession");
status_t result = DRM_ERROR_CANNOT_HANDLE;
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
@@ -324,18 +373,15 @@
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
result = rDrmEngine.openDecryptSession(uniqueId, handle, fd, offset, length);
- LOGV("plug-in %s return value = %d", plugInId.string(), result);
-
if (DRM_NO_ERROR == result) {
++mDecryptSessionId;
mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
- LOGV("plug-in %s is selected", plugInId.string());
break;
}
}
}
- if (DRM_ERROR_CANNOT_HANDLE == result) {
+ if (DRM_NO_ERROR != result) {
delete handle; handle = NULL;
LOGE("DrmManager::openDecryptSession: no capable plug-in found");
}
@@ -343,39 +389,47 @@
return handle;
}
-void DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+ status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
- drmEngine->closeDecryptSession(uniqueId, decryptHandle);
-
- mDecryptSessionMap.removeItem(decryptHandle->decryptId);
+ result = drmEngine->closeDecryptSession(uniqueId, decryptHandle);
+ if (DRM_NO_ERROR == result) {
+ mDecryptSessionMap.removeItem(decryptHandle->decryptId);
+ }
}
+ return result;
}
-void DrmManager::initializeDecryptUnit(
+status_t DrmManager::initializeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+ status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
- drmEngine->initializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
+ result = drmEngine->initializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
}
+ return result;
}
-status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
- status_t status = DRM_ERROR_UNKNOWN;
+status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+ status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
- status = drmEngine->decrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+ result = drmEngine->decrypt(
+ uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
}
- return status;
+ return result;
}
-void DrmManager::finalizeDecryptUnit(
+status_t DrmManager::finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
- drmEngine->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+ result = drmEngine->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
}
+ return result;
}
ssize_t DrmManager::pread(int uniqueId, DecryptHandle* decryptHandle,
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 9d000e9..843dddb 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "DrmManagerService(Native)"
#include <utils/Log.h>
@@ -29,20 +29,23 @@
#define SUCCESS 0
#define DRM_DIRECTORY_PERMISSION 0700
+#define DRM_PLUGINS_ROOT "/data/drm/plugins"
+#define DRM_PLUGINS_NATIVE "/data/drm/plugins/native"
+#define DRM_PLUGINS_NATIVE_DATABASES "/data/drm/plugins/native/databases"
void DrmManagerService::instantiate() {
LOGV("instantiate");
- int res = mkdir("/data/drm/plugins", DRM_DIRECTORY_PERMISSION);
- if (SUCCESS == res || EEXIST == errno) {
- res = mkdir("/data/drm/plugins/native", DRM_DIRECTORY_PERMISSION);
- if (SUCCESS == res || EEXIST == errno) {
- res = mkdir("/data/drm/plugins/native/databases", DRM_DIRECTORY_PERMISSION);
- if (SUCCESS == res || EEXIST == errno) {
- defaultServiceManager()
- ->addService(String16("drm.drmManager"), new DrmManagerService());
- }
- }
+ int res = mkdir(DRM_PLUGINS_ROOT, DRM_DIRECTORY_PERMISSION);
+ if (SUCCESS == res || EEXIST == errno) {
+ res = mkdir(DRM_PLUGINS_NATIVE, DRM_DIRECTORY_PERMISSION);
+ if (SUCCESS == res || EEXIST == errno) {
+ res = mkdir(DRM_PLUGINS_NATIVE_DATABASES, DRM_DIRECTORY_PERMISSION);
+ if (SUCCESS == res || EEXIST == errno) {
+ defaultServiceManager()
+ ->addService(String16("drm.drmManager"), new DrmManagerService());
+ }
+ }
}
}
@@ -57,6 +60,14 @@
delete mDrmManager; mDrmManager = NULL;
}
+int DrmManagerService::addUniqueId(int uniqueId) {
+ return mDrmManager->addUniqueId(uniqueId);
+}
+
+void DrmManagerService::removeUniqueId(int uniqueId) {
+ mDrmManager->removeUniqueId(uniqueId);
+}
+
status_t DrmManagerService::loadPlugIns(int uniqueId) {
LOGV("Entering load plugins");
return mDrmManager->loadPlugIns(uniqueId);
@@ -105,7 +116,7 @@
return mDrmManager->acquireDrmInfo(uniqueId, drmInfoRequest);
}
-void DrmManagerService::saveRights(
+status_t DrmManagerService::saveRights(
int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
LOGV("Entering saveRights");
@@ -129,16 +140,16 @@
return mDrmManager->checkRightsStatus(uniqueId, path, action);
}
-void DrmManagerService::consumeRights(
+status_t DrmManagerService::consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
LOGV("Entering consumeRights");
- mDrmManager->consumeRights(uniqueId, decryptHandle, action, reserve);
+ return mDrmManager->consumeRights(uniqueId, decryptHandle, action, reserve);
}
-void DrmManagerService::setPlaybackStatus(
+status_t DrmManagerService::setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
LOGV("Entering setPlaybackStatus");
- mDrmManager->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
+ return mDrmManager->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
}
bool DrmManagerService::validateAction(
@@ -148,14 +159,14 @@
return mDrmManager->validateAction(uniqueId, path, action, description);
}
-void DrmManagerService::removeRights(int uniqueId, const String8& path) {
+status_t DrmManagerService::removeRights(int uniqueId, const String8& path) {
LOGV("Entering removeRights");
- mDrmManager->removeRights(uniqueId, path);
+ return mDrmManager->removeRights(uniqueId, path);
}
-void DrmManagerService::removeAllRights(int uniqueId) {
+status_t DrmManagerService::removeAllRights(int uniqueId) {
LOGV("Entering removeAllRights");
- mDrmManager->removeAllRights(uniqueId);
+ return mDrmManager->removeAllRights(uniqueId);
}
int DrmManagerService::openConvertSession(int uniqueId, const String8& mimeType) {
@@ -186,28 +197,28 @@
return mDrmManager->openDecryptSession(uniqueId, fd, offset, length);
}
-void DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
LOGV("Entering closeDecryptSession");
- mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
+ return mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
}
-void DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
LOGV("Entering initializeDecryptUnit");
- mDrmManager->initializeDecryptUnit(uniqueId,decryptHandle, decryptUnitId, headerInfo);
+ return mDrmManager->initializeDecryptUnit(uniqueId,decryptHandle, decryptUnitId, headerInfo);
}
status_t DrmManagerService::decrypt(
- int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+ int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
LOGV("Entering decrypt");
- return mDrmManager->decrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+ return mDrmManager->decrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
}
-void DrmManagerService::finalizeDecryptUnit(
+status_t DrmManagerService::finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
LOGV("Entering finalizeDecryptUnit");
- mDrmManager->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+ return mDrmManager->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
}
ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle,
diff --git a/drm/drmserver/StringTokenizer.cpp b/drm/drmserver/StringTokenizer.cpp
index 367c9bd..2130a00 100644
--- a/drm/drmserver/StringTokenizer.cpp
+++ b/drm/drmserver/StringTokenizer.cpp
@@ -45,12 +45,10 @@
StringTokenizer::Iterator::Iterator(const StringTokenizer::Iterator& iterator) :
mStringTokenizer(iterator.mStringTokenizer),
mIndex(iterator.mIndex) {
- LOGV("StringTokenizer::Iterator::Iterator");
}
StringTokenizer::Iterator& StringTokenizer::Iterator::operator=(
const StringTokenizer::Iterator& iterator) {
- LOGV("StringTokenizer::Iterator::operator=");
mStringTokenizer = iterator.mStringTokenizer;
mIndex = iterator.mIndex;
return *this;
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
new file mode 100644
index 0000000..8e71634
--- /dev/null
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 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.drm;
+
+/**
+ * This is an entity class which would be passed to caller in
+ * {@link DrmManagerClient.OnErrorListener#onError(DrmManagerClient, DrmErrorEvent)}
+ *
+ */
+public class DrmErrorEvent extends DrmEvent {
+ /**
+ * TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights.
+ */
+ public static final int TYPE_RIGHTS_NOT_INSTALLED = 2001;
+ /**
+ * TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights.
+ */
+ public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002;
+ /**
+ * TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent.
+ */
+ public static final int TYPE_NOT_SUPPORTED = 2003;
+ /**
+ * TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal.
+ * Can in the future perhaps be used to trigger garbage collector.
+ */
+ public static final int TYPE_OUT_OF_MEMORY = 2004;
+ /**
+ * TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt
+ * can be made to renew rights.
+ */
+ public static final int TYPE_NO_INTERNET_CONNECTION = 2005;
+ /**
+ * TYPE_REGISTRATION_FAILED, when failed to register with the service.
+ */
+ public static final int TYPE_REGISTRATION_FAILED = 2006;
+ /**
+ * TYPE_UNREGISTRATION_FAILED, when failed to unregister with the service.
+ */
+ public static final int TYPE_UNREGISTRATION_FAILED = 2007;
+ /**
+ * TYPE_RIGHTS_ACQUISITION_FAILED, when failed to acquire the rights information required.
+ */
+ public static final int TYPE_RIGHTS_ACQUISITION_FAILED = 2008;
+ /**
+ * TYPE_INITIALIZE_FAILED, when failed to load and initialize the available plugins.
+ */
+ public static final int TYPE_INITIALIZE_FAILED = 2009;
+ /**
+ * TYPE_FINALIZE_FAILED, when failed to unload and finalize the loaded plugins.
+ */
+ public static final int TYPE_FINALIZE_FAILED = 2010;
+ /**
+ * TYPE_REMOVE_ALL_RIGHTS_FAILED, when failed to remove all the rights objects
+ * associated with all DRM schemes.
+ */
+ public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2011;
+ /**
+ * TYPE_DRM_INFO_ACQUISITION_FAILED, when failed to get the required information to
+ * communicate with the service.
+ */
+ public static final int TYPE_DRM_INFO_ACQUISITION_FAILED = 2012;
+
+ /**
+ * constructor to create DrmErrorEvent object with given parameters
+ *
+ * @param uniqueId Unique session identifier
+ * @param type Type of information
+ * @param message Message description
+ */
+ public DrmErrorEvent(int uniqueId, int type, String message) {
+ super(uniqueId, type, message);
+ }
+}
+
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
index 44c4b43..d6e0c3a 100644
--- a/drm/java/android/drm/DrmEvent.java
+++ b/drm/java/android/drm/DrmEvent.java
@@ -22,6 +22,40 @@
*
*/
public class DrmEvent {
+ /**
+ * Constant field signifies that unload and finalize the loaded plugins successfully
+ */
+ public static final int TYPE_FINALIZED = 1001;
+ /**
+ * Constant field signifies that register with the service successfully
+ */
+ public static final int TYPE_REGISTERED = 1002;
+ /**
+ * Constant field signifies that load and initialized the available plugins successfully
+ */
+ public static final int TYPE_INITIALIZED = 1003;
+ /**
+ * Constant field signifies that unregister with the service successfully
+ */
+ public static final int TYPE_UNREGISTERED = 1004;
+ /**
+ * Constant field signifies that rights information is acquired successfully
+ */
+ public static final int TYPE_RIGHTS_ACQUIRED = 1005;
+ /**
+ * Constant field signifies that all the rights information associated with
+ * all DRM schemes are removed successfully
+ */
+ public static final int TYPE_ALL_RIGHTS_REMOVED = 1006;
+ /**
+ * Constant field signifies that the required information to communicate with
+ * the service is acquired sucessfully
+ */
+ public static final int TYPE_DRM_INFO_ACQUIRED = 1007;
+
+ public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
+ public static final String DRM_INFO_OBJECT = "drm_info_object";
+
private final int mUniqueId;
private final int mType;
private String mMessage = "";
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
index be1b009..a778e06 100644
--- a/drm/java/android/drm/DrmInfoEvent.java
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -26,42 +26,25 @@
* TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT, when registration has been already done
* by another account ID.
*/
- public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 0x0000001;
+ public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1;
/**
* TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
*/
- public static final int TYPE_REMOVE_RIGHTS = 0x0000002;
+ public static final int TYPE_REMOVE_RIGHTS = 2;
/**
* TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
*/
- public static final int TYPE_RIGHTS_INSTALLED = 0x0000003;
- /**
- * TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights.
- */
- public static final int TYPE_RIGHTS_NOT_INSTALLED = 0x0000004;
- /**
- * TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights.
- */
- public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 0x0000005;
- /**
- * TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent.
- */
- public static final int TYPE_NOT_SUPPORTED = 0x0000006;
+ public static final int TYPE_RIGHTS_INSTALLED = 3;
/**
* TYPE_WAIT_FOR_RIGHTS, rights object is on it's way to phone,
* wait before calling checkRights again.
*/
- public static final int TYPE_WAIT_FOR_RIGHTS = 0x0000007;
+ public static final int TYPE_WAIT_FOR_RIGHTS = 4;
/**
- * TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal.
- * Can in the future perhaps be used to trigger garbage collector.
+ * TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
+ * already done for the given account.
*/
- public static final int TYPE_OUT_OF_MEMORY = 0x0000008;
- /**
- * TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt
- * can be made to renew rights.
- */
- public static final int TYPE_NO_INTERNET_CONNECTION = 0x0000009;
+ public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
/**
* constructor to create DrmInfoEvent object with given parameters
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 7ec70da..147c530 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -18,14 +18,19 @@
import android.content.ContentValues;
import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.provider.MediaStore;
import android.util.Log;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.HashMap;
/**
* Interface of DRM Framework.
@@ -34,7 +39,16 @@
*
*/
public class DrmManagerClient {
- private static final String TAG = "DrmManager";
+ /**
+ * Constant field signifies the success or no error occurred
+ */
+ public static final int ERROR_NONE = 0;
+ /**
+ * Constant field signifies that error occurred and the reason is not known
+ */
+ public static final int ERROR_UNKNOWN = -2000;
+
+ private static final String TAG = "DrmManagerClient";
static {
// Load the respective library
@@ -55,55 +69,189 @@
public void onInfo(DrmManagerClient client, DrmInfoEvent event);
}
- private static final int STATE_UNINITIALIZED = 0x00000000;
- private static final int STATE_INITIALIZED = 0x00000001;
+ /**
+ * Interface definition of a callback to be invoked to communicate
+ * the result of time consuming APIs asynchronously
+ */
+ public interface OnEventListener {
+ /**
+ * Called to indicate the result of asynchronous APIs.
+ *
+ * @param client DrmManagerClient instance
+ * @param event instance which wraps type and message
+ * @param attributes resultant values in key and value pair.
+ */
+ public void onEvent(DrmManagerClient client, DrmEvent event,
+ HashMap<String, Object> attributes);
+ }
+
+ /**
+ * Interface definition of a callback to be invoked to communicate
+ * the error occurred
+ */
+ public interface OnErrorListener {
+ /**
+ * Called to indicate the error occurred.
+ *
+ * @param client DrmManagerClient instance
+ * @param event instance which wraps error type and message
+ */
+ public void onError(DrmManagerClient client, DrmErrorEvent event);
+ }
+
+ private static final int STATE_UNINITIALIZED = 0;
+ private static final int STATE_INITIALIZED = 1;
+
+ private static final int ACTION_INITIALIZE = 1000;
+ private static final int ACTION_FINALIZE = 1001;
+ private static final int ACTION_REMOVE_ALL_RIGHTS = 1002;
+ private static final int ACTION_ACQUIRE_DRM_INFO = 1003;
+ private static final int ACTION_PROCESS_DRM_INFO = 1004;
private int mUniqueId;
private int mNativeContext;
+ private Context mContext;
+ private InfoHandler mInfoHandler;
private EventHandler mEventHandler;
private OnInfoListener mOnInfoListener;
+ private OnEventListener mOnEventListener;
+ private OnErrorListener mOnErrorListener;
private int mCurrentState = STATE_UNINITIALIZED;
- /**
- * {@hide}
- */
- public static void notify(Object thisReference, int uniqueId, int infoType, String message) {
- DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get();
-
- if (null != instance && null != instance.mEventHandler) {
- Message m = instance.mEventHandler.obtainMessage(
- EventHandler.INFO_EVENT_TYPE, uniqueId, infoType, message);
- instance.mEventHandler.sendMessage(m);
- }
- }
-
private class EventHandler extends Handler {
- public static final int INFO_EVENT_TYPE = 1;
public EventHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
+ DrmEvent event = null;
+ DrmErrorEvent error = null;
+ HashMap<String, Object> attributes = new HashMap<String, Object>();
+
+ switch(msg.what) {
+ case ACTION_INITIALIZE: {
+ if (ERROR_NONE == _loadPlugIns(mUniqueId, msg.obj)) {
+ mCurrentState = STATE_INITIALIZED;
+ event = new DrmEvent(mUniqueId, DrmEvent.TYPE_INITIALIZED, null);
+ } else {
+ error = new DrmErrorEvent(mUniqueId,
+ DrmErrorEvent.TYPE_INITIALIZE_FAILED, null);
+ }
+ break;
+ }
+ case ACTION_ACQUIRE_DRM_INFO: {
+ final DrmInfoRequest request = (DrmInfoRequest) msg.obj;
+ DrmInfo drmInfo = _acquireDrmInfo(mUniqueId, request);
+ if (null != drmInfo) {
+ attributes.put(DrmEvent.DRM_INFO_OBJECT, drmInfo);
+ event = new DrmEvent(mUniqueId, DrmEvent.TYPE_DRM_INFO_ACQUIRED, null);
+ } else {
+ error = new DrmErrorEvent(mUniqueId,
+ DrmErrorEvent.TYPE_DRM_INFO_ACQUISITION_FAILED, null);
+ }
+ break;
+ }
+ case ACTION_PROCESS_DRM_INFO: {
+ final DrmInfo drmInfo = (DrmInfo) msg.obj;
+ DrmInfoStatus status = _processDrmInfo(mUniqueId, drmInfo);
+ if (null != status && DrmInfoStatus.STATUS_OK == status.statusCode) {
+ attributes.put(DrmEvent.DRM_INFO_STATUS_OBJECT, status);
+ event = new DrmEvent(mUniqueId, getEventType(drmInfo.getInfoType()), null);
+ } else {
+ error = new DrmErrorEvent(mUniqueId,
+ getErrorType(drmInfo.getInfoType()), null);
+ }
+ break;
+ }
+ case ACTION_REMOVE_ALL_RIGHTS: {
+ if (ERROR_NONE == _removeAllRights(mUniqueId)) {
+ event = new DrmEvent(mUniqueId, DrmEvent.TYPE_ALL_RIGHTS_REMOVED, null);
+ } else {
+ error = new DrmErrorEvent(mUniqueId,
+ DrmErrorEvent.TYPE_REMOVE_ALL_RIGHTS_FAILED, null);
+ }
+ break;
+ }
+ case ACTION_FINALIZE: {
+ if (ERROR_NONE == _unloadPlugIns(mUniqueId)) {
+ mCurrentState = STATE_UNINITIALIZED;
+ event = new DrmEvent(mUniqueId, DrmEvent.TYPE_FINALIZED, null);
+ } else {
+ error = new DrmErrorEvent(mUniqueId,
+ DrmErrorEvent.TYPE_FINALIZE_FAILED, null);
+ }
+ break;
+ }
+ default:
+ Log.e(TAG, "Unknown message type " + msg.what);
+ return;
+ }
+ if (null != mOnEventListener && null != event) {
+ mOnEventListener.onEvent(DrmManagerClient.this, event, attributes);
+ }
+ if (null != mOnErrorListener && null != error) {
+ mOnErrorListener.onError(DrmManagerClient.this, error);
+ }
+ }
+ }
+
+ /**
+ * {@hide}
+ */
+ public static void notify(
+ Object thisReference, int uniqueId, int infoType, String message) {
+ DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get();
+
+ if (null != instance && null != instance.mInfoHandler) {
+ Message m = instance.mInfoHandler.obtainMessage(
+ InfoHandler.INFO_EVENT_TYPE, uniqueId, infoType, message);
+ instance.mInfoHandler.sendMessage(m);
+ }
+ }
+
+ private class InfoHandler extends Handler {
+ public static final int INFO_EVENT_TYPE = 1;
+
+ public InfoHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void handleMessage(Message msg) {
+ DrmInfoEvent event = null;
+ DrmErrorEvent error = null;
switch (msg.what) {
- case EventHandler.INFO_EVENT_TYPE:
+ case InfoHandler.INFO_EVENT_TYPE:
int uniqueId = msg.arg1;
int infoType = msg.arg2;
String message = msg.obj.toString();
- if (infoType == DrmInfoEvent.TYPE_REMOVE_RIGHTS) {
+ switch (infoType) {
+ case DrmInfoEvent.TYPE_REMOVE_RIGHTS: {
try {
DrmUtils.removeFile(message);
} catch (IOException e) {
e.printStackTrace();
}
+ event = new DrmInfoEvent(uniqueId, infoType, message);
+ break;
+ }
+ case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT: {
+ event = new DrmInfoEvent(uniqueId, infoType, message);
+ break;
+ }
+ default:
+ error = new DrmErrorEvent(uniqueId, infoType, message);
+ break;
}
- if (null != mOnInfoListener) {
- DrmInfoEvent event = new DrmInfoEvent(uniqueId, infoType, message);
+ if (null != mOnInfoListener && null != event) {
mOnInfoListener.onInfo(DrmManagerClient.this, event);
}
+ if (null != mOnErrorListener && null != error) {
+ mOnErrorListener.onError(DrmManagerClient.this, error);
+ }
return;
default:
Log.e(TAG, "Unknown message type " + msg.what);
@@ -118,31 +266,58 @@
* @param context context of the caller
*/
public DrmManagerClient(Context context) {
+ mContext = context;
Looper looper;
if (null != (looper = Looper.myLooper())) {
- mEventHandler = new EventHandler(looper);
+ mInfoHandler = new InfoHandler(looper);
} else if (null != (looper = Looper.getMainLooper())) {
- mEventHandler = new EventHandler(looper);
+ mInfoHandler = new InfoHandler(looper);
} else {
- mEventHandler = null;
+ mInfoHandler = null;
}
+ HandlerThread thread = new HandlerThread("DrmManagerClient.EventHandler");
+ thread.start();
+ mEventHandler = new EventHandler(thread.getLooper());
+
// save the unique id
mUniqueId = hashCode();
}
/**
* Register a callback to be invoked when the caller required to receive
- * necessary information
+ * supplementary information.
*
* @param infoListener
*/
- public void setOnInfoListener(OnInfoListener infoListener) {
- synchronized(this) {
- if (null != infoListener) {
- mOnInfoListener = infoListener;
- }
+ public synchronized void setOnInfoListener(OnInfoListener infoListener) {
+ if (null != infoListener) {
+ mOnInfoListener = infoListener;
+ }
+ }
+
+ /**
+ * Register a callback to be invoked when the caller required to receive
+ * the result of asynchronous APIs.
+ *
+ * @param eventListener
+ */
+ public synchronized void setOnEventListener(OnEventListener eventListener) {
+ if (null != eventListener) {
+ mOnEventListener = eventListener;
+ }
+ }
+
+ /**
+ * Register a callback to be invoked when the caller required to receive
+ * error result of asynchronous APIs.
+ *
+ * @param errorListener
+ */
+ public synchronized void setOnErrorListener(OnErrorListener errorListener) {
+ if (null != errorListener) {
+ mOnErrorListener = errorListener;
}
}
@@ -150,25 +325,43 @@
* Initializes DrmFramework, which loads all available plug-ins
* in the default plug-in directory path
*
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
*/
- public void loadPlugIns() {
- if (getState() == STATE_UNINITIALIZED) {
- _loadPlugIns(mUniqueId, new WeakReference<DrmManagerClient>(this));
-
- mCurrentState = STATE_INITIALIZED;
+ public int loadPlugIns() {
+ int result = ERROR_UNKNOWN;
+ if (STATE_UNINITIALIZED == getState()) {
+ if (null != mEventHandler) {
+ Message msg = mEventHandler.obtainMessage(
+ ACTION_INITIALIZE, new WeakReference<DrmManagerClient>(this));
+ result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+ }
+ } else {
+ result = ERROR_NONE;
}
+ return result;
}
/**
* Finalize DrmFramework, which release resources associated with each plug-in
* and unload all plug-ins.
+ *
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
*/
- public void unloadPlugIns() {
- if (getState() == STATE_INITIALIZED) {
- _unloadPlugIns(mUniqueId);
-
- mCurrentState = STATE_UNINITIALIZED;
+ public int unloadPlugIns() {
+ int result = ERROR_UNKNOWN;
+ if (STATE_INITIALIZED == getState()) {
+ if (null != mEventHandler) {
+ Message msg = mEventHandler.obtainMessage(ACTION_FINALIZE);
+ result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+ }
+ } else {
+ result = ERROR_NONE;
}
+ return result;
}
/**
@@ -177,7 +370,7 @@
* @return Array of DrmEngine plug-in strings
*/
public String[] getAvailableDrmEngines() {
- if (getState() == STATE_UNINITIALIZED) {
+ if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
@@ -203,13 +396,25 @@
public ContentValues getConstraints(String path, int action) {
if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
throw new IllegalArgumentException("Given usage or path is invalid/null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _getConstraints(mUniqueId, path, action);
}
/**
+ * Get constraints information evaluated from DRM content
+ *
+ * @param uri The Content URI of the data
+ * @param action Actions defined in {@link DrmStore.Action}
+ * @return ContentValues instance in which constraints key-value pairs are embedded
+ * or null in case of failure
+ */
+ public ContentValues getConstraints(Uri uri, int action) {
+ return getConstraints(convertUriToPath(uri), action);
+ }
+
+ /**
* Save DRM rights to specified rights path
* and make association with content path.
*
@@ -218,20 +423,22 @@
* @param drmRights DrmRights to be saved
* @param rightsPath File path where rights to be saved
* @param contentPath File path where content was saved
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
* @throws IOException if failed to save rights information in the given path
*/
- public void saveRights(
+ public int saveRights(
DrmRights drmRights, String rightsPath, String contentPath) throws IOException {
- if (null == drmRights || !drmRights.isValid()
- || null == contentPath || contentPath.equals("")) {
+ if (null == drmRights || !drmRights.isValid()) {
throw new IllegalArgumentException("Given drmRights or contentPath is not valid");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
if (null != rightsPath && !rightsPath.equals("")) {
DrmUtils.writeToFile(rightsPath, drmRights.getData());
}
- _saveRights(mUniqueId, drmRights, rightsPath, contentPath);
+ return _saveRights(mUniqueId, drmRights, rightsPath, contentPath);
}
/**
@@ -244,7 +451,7 @@
if (null == engineFilePath || engineFilePath.equals("")) {
throw new IllegalArgumentException(
"Given engineFilePath: "+ engineFilePath + "is not valid");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
_installDrmEngine(mUniqueId, engineFilePath);
@@ -256,47 +463,78 @@
* @param path Path of the content to be handled
* @param mimeType Mimetype of the object to be handled
* @return
- * true - if the given mimeType or path can be handled.
- * false - cannot be handled. false will be returned in case
+ * true - if the given mimeType or path can be handled
+ * false - cannot be handled. false will be return in case
* the state is uninitialized
*/
public boolean canHandle(String path, String mimeType) {
if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
throw new IllegalArgumentException("Path or the mimetype should be non null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _canHandle(mUniqueId, path, mimeType);
}
/**
+ * Check whether the given mimetype or uri can be handled.
+ *
+ * @param uri The content URI of the data
+ * @param mimeType Mimetype of the object to be handled
+ * @return
+ * true - if the given mimeType or path can be handled
+ * false - cannot be handled. false will be return in case
+ * the state is uninitialized
+ */
+ public boolean canHandle(Uri uri, String mimeType) {
+ if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
+ throw new IllegalArgumentException("Uri or the mimetype should be non null");
+ }
+ return canHandle(convertUriToPath(uri), mimeType);
+ }
+
+ /**
* Executes given drm information based on its type
*
* @param drmInfo Information needs to be processed
- * @return DrmInfoStatus Instance as a result of processing given input
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
*/
- public DrmInfoStatus processDrmInfo(DrmInfo drmInfo) {
+ public int processDrmInfo(DrmInfo drmInfo) {
if (null == drmInfo || !drmInfo.isValid()) {
throw new IllegalArgumentException("Given drmInfo is invalid/null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
- return _processDrmInfo(mUniqueId, drmInfo);
+ int result = ERROR_UNKNOWN;
+ if (null != mEventHandler) {
+ Message msg = mEventHandler.obtainMessage(ACTION_PROCESS_DRM_INFO, drmInfo);
+ result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+ }
+ return result;
}
/**
* Retrieves necessary information for register, unregister or rights acquisition.
*
* @param drmInfoRequest Request information to retrieve drmInfo
- * @return DrmInfo Instance as a result of processing given input
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
*/
- public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
+ public int acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
throw new IllegalArgumentException("Given drmInfoRequest is invalid/null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
- return _acquireDrmInfo(mUniqueId, drmInfoRequest);
+ int result = ERROR_UNKNOWN;
+ if (null != mEventHandler) {
+ Message msg = mEventHandler.obtainMessage(ACTION_ACQUIRE_DRM_INFO, drmInfoRequest);
+ result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+ }
+ return result;
}
/**
@@ -312,13 +550,37 @@
public int getDrmObjectType(String path, String mimeType) {
if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
throw new IllegalArgumentException("Path or the mimetype should be non null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _getDrmObjectType(mUniqueId, path, mimeType);
}
/**
+ * Retrieves the type of the protected object (content, rights, etc..)
+ * using specified uri or mimetype. At least one parameter should be non null
+ * to retrieve DRM object type
+ *
+ * @param uri The content URI of the data
+ * @param mimeType Mimetype of the content or null.
+ * @return Type of the DRM content.
+ * @see DrmStore.DrmObjectType
+ */
+ public int getDrmObjectType(Uri uri, String mimeType) {
+ if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
+ throw new IllegalArgumentException("Uri or the mimetype should be non null");
+ }
+ String path = "";
+ try {
+ path = convertUriToPath(uri);
+ } catch (Exception e) {
+ // Even uri is invalid the mimetype shall be valid, so allow to proceed further.
+ Log.w(TAG, "Given Uri could not be found in media store");
+ }
+ return getDrmObjectType(path, mimeType);
+ }
+
+ /**
* Retrieves the mime type embedded inside the original content
*
* @param path Path of the protected content
@@ -327,13 +589,26 @@
public String getOriginalMimeType(String path) {
if (null == path || path.equals("")) {
throw new IllegalArgumentException("Given path should be non null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _getOriginalMimeType(mUniqueId, path);
}
/**
+ * Retrieves the mime type embedded inside the original content
+ *
+ * @param uri The content URI of the data
+ * @return Mimetype of the original content, such as "video/mpeg"
+ */
+ public String getOriginalMimeType(Uri uri) {
+ if (null == uri || Uri.EMPTY == uri) {
+ throw new IllegalArgumentException("Given uri is not valid");
+ }
+ return getOriginalMimeType(convertUriToPath(uri));
+ }
+
+ /**
* Check whether the given content has valid rights or not
*
* @param path Path of the protected content
@@ -345,6 +620,20 @@
}
/**
+ * Check whether the given content has valid rights or not
+ *
+ * @param uri The content URI of the data
+ * @return Status of the rights for the protected content
+ * @see DrmStore.RightsStatus
+ */
+ public int checkRightsStatus(Uri uri) {
+ if (null == uri || Uri.EMPTY == uri) {
+ throw new IllegalArgumentException("Given uri is not valid");
+ }
+ return checkRightsStatus(convertUriToPath(uri));
+ }
+
+ /**
* Check whether the given content has valid rights or not for specified action.
*
* @param path Path of the protected content
@@ -355,35 +644,77 @@
public int checkRightsStatus(String path, int action) {
if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
throw new IllegalArgumentException("Given path or action is not valid");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _checkRightsStatus(mUniqueId, path, action);
}
/**
+ * Check whether the given content has valid rights or not for specified action.
+ *
+ * @param uri The content URI of the data
+ * @param action Action to perform
+ * @return Status of the rights for the protected content
+ * @see DrmStore.RightsStatus
+ */
+ public int checkRightsStatus(Uri uri, int action) {
+ if (null == uri || Uri.EMPTY == uri) {
+ throw new IllegalArgumentException("Given uri is not valid");
+ }
+ return checkRightsStatus(convertUriToPath(uri), action);
+ }
+
+ /**
* Removes the rights associated with the given protected content
*
* @param path Path of the protected content
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
*/
- public void removeRights(String path) {
+ public int removeRights(String path) {
if (null == path || path.equals("")) {
throw new IllegalArgumentException("Given path should be non null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
- _removeRights(mUniqueId, path);
+ return _removeRights(mUniqueId, path);
+ }
+
+ /**
+ * Removes the rights associated with the given protected content
+ *
+ * @param uri The content URI of the data
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
+ */
+ public int removeRights(Uri uri) {
+ if (null == uri || Uri.EMPTY == uri) {
+ throw new IllegalArgumentException("Given uri is not valid");
+ }
+ return removeRights(convertUriToPath(uri));
}
/**
* Removes all the rights information of every plug-in associated with
* DRM framework. Will be used in master reset
+ *
+ * @return
+ * ERROR_NONE for success
+ * ERROR_UNKNOWN for failure
*/
- public void removeAllRights() {
- if (getState() == STATE_UNINITIALIZED) {
+ public int removeAllRights() {
+ if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
- _removeAllRights(mUniqueId);
+ int result = ERROR_UNKNOWN;
+ if (null != mEventHandler) {
+ Message msg = mEventHandler.obtainMessage(ACTION_REMOVE_ALL_RIGHTS);
+ result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
+ }
+ return result;
}
/**
@@ -398,7 +729,7 @@
public int openConvertSession(String mimeType) {
if (null == mimeType || mimeType.equals("")) {
throw new IllegalArgumentException("Path or the mimeType should be non null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _openConvertSession(mUniqueId, mimeType);
@@ -419,7 +750,7 @@
public DrmConvertedStatus convertData(int convertId, byte[] inputData) {
if (null == inputData || 0 >= inputData.length) {
throw new IllegalArgumentException("Given inputData should be non null");
- } else if (getState() == STATE_UNINITIALIZED) {
+ } else if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _convertData(mUniqueId, convertId, inputData);
@@ -438,7 +769,7 @@
* the application on which offset these signature data should be appended.
*/
public DrmConvertedStatus closeConvertSession(int convertId) {
- if (getState() == STATE_UNINITIALIZED) {
+ if (STATE_UNINITIALIZED == getState()) {
throw new IllegalStateException("Not Initialized yet");
}
return _closeConvertSession(mUniqueId, convertId);
@@ -448,10 +779,68 @@
return mCurrentState;
}
- // private native interfaces
- private native void _loadPlugIns(int uniqueId, Object weak_this);
+ private int getEventType(int infoType) {
+ int eventType = -1;
- private native void _unloadPlugIns(int uniqueId);
+ switch (infoType) {
+ case DrmInfoRequest.TYPE_REGISTRATION_INFO:
+ eventType = DrmEvent.TYPE_REGISTERED;
+ break;
+ case DrmInfoRequest.TYPE_UNREGISTRATION_INFO:
+ eventType = DrmEvent.TYPE_UNREGISTERED;
+ break;
+ case DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO:
+ eventType = DrmEvent.TYPE_RIGHTS_ACQUIRED;
+ break;
+ }
+ return eventType;
+ }
+
+ private int getErrorType(int infoType) {
+ int error = -1;
+
+ switch (infoType) {
+ case DrmInfoRequest.TYPE_REGISTRATION_INFO:
+ error = DrmErrorEvent.TYPE_REGISTRATION_FAILED;
+ break;
+ case DrmInfoRequest.TYPE_UNREGISTRATION_INFO:
+ error = DrmErrorEvent.TYPE_UNREGISTRATION_FAILED;
+ break;
+ case DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO:
+ error = DrmErrorEvent.TYPE_RIGHTS_ACQUISITION_FAILED;
+ break;
+ }
+ return error;
+ }
+
+ /**
+ * This method expects uri in the following format
+ * content://media/<table_name>/<row_index> (or)
+ * file://sdcard/test.mp4
+ *
+ * Here <table_name> shall be "video" or "audio" or "images"
+ * <row_index> the index of the content in given table
+ */
+ private String convertUriToPath(Uri uri) {
+ String scheme = uri.getScheme();
+ if (null == scheme || scheme.equals("file")) {
+ return uri.getPath();
+ }
+ String[] projection = new String[] {MediaStore.MediaColumns.DATA};
+ Cursor cursor = mContext.getContentResolver().query(uri, projection, null, null, null);
+ if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
+ throw new IllegalArgumentException("Given Uri could not be found in media store");
+ }
+ int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
+ String path = cursor.getString(pathIndex);
+ cursor.close();
+ return path;
+ }
+
+ // private native interfaces
+ private native int _loadPlugIns(int uniqueId, Object weak_this);
+
+ private native int _unloadPlugIns(int uniqueId);
private native void _installDrmEngine(int uniqueId, String engineFilepath);
@@ -463,7 +852,7 @@
private native DrmInfo _acquireDrmInfo(int uniqueId, DrmInfoRequest drmInfoRequest);
- private native void _saveRights(
+ private native int _saveRights(
int uniqueId, DrmRights drmRights, String rightsPath, String contentPath);
private native int _getDrmObjectType(int uniqueId, String path, String mimeType);
@@ -472,13 +861,14 @@
private native int _checkRightsStatus(int uniqueId, String path, int action);
- private native void _removeRights(int uniqueId, String path);
+ private native int _removeRights(int uniqueId, String path);
- private native void _removeAllRights(int uniqueId);
+ private native int _removeAllRights(int uniqueId);
private native int _openConvertSession(int uniqueId, String mimeType);
- private native DrmConvertedStatus _convertData(int uniqueId, int convertId, byte[] inputData);
+ private native DrmConvertedStatus _convertData(
+ int uniqueId, int convertId, byte[] inputData);
private native DrmConvertedStatus _closeConvertSession(int uniqueId, int convertId);
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index bc5a7bf..6158b66 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "DrmManager-JNI"
#include <utils/Log.h>
@@ -76,7 +76,7 @@
env->ReleaseStringUTFChars(valueString, bytes);
delete [] data; data = NULL;
} else {
- LOGD("Failed to retrieve the data from the field %s", fieldName);
+ LOGV("Failed to retrieve the data from the field %s", fieldName);
}
}
return dataString;
@@ -223,7 +223,7 @@
return sp<DrmManagerClientImpl>(client);
}
-static void android_drm_DrmManagerClient_loadPlugIns(
+static jint android_drm_DrmManagerClient_loadPlugIns(
JNIEnv* env, jobject thiz, jint uniqueId, jobject weak_thiz) {
LOGV("load plugins - Enter");
@@ -235,23 +235,26 @@
setDrmManagerClientImpl(env, thiz, drmManager);
- getDrmManagerClientImpl(env, thiz)->loadPlugIns(uniqueId);
LOGV("load plugins - Exit");
+ return getDrmManagerClientImpl(env, thiz)->loadPlugIns(uniqueId);
}
-static void android_drm_DrmManagerClient_unloadPlugIns(JNIEnv* env, jobject thiz, jint uniqueId) {
+static jint android_drm_DrmManagerClient_unloadPlugIns(JNIEnv* env, jobject thiz, jint uniqueId) {
LOGV("unload plugins - Enter");
sp<DrmManagerClientImpl> client = getDrmManagerClientImpl(env, thiz);
- client->unloadPlugIns(uniqueId);
- client->setOnInfoListener(uniqueId, NULL);
+
DrmManagerClientImpl::remove(uniqueId);
+ int result = client->unloadPlugIns(uniqueId);
+ if (DRM_NO_ERROR == result) {
+ client->setOnInfoListener(uniqueId, NULL);
- sp<DrmManagerClientImpl> oldClient = setDrmManagerClientImpl(env, thiz, NULL);
- if (oldClient != NULL) {
- oldClient->setOnInfoListener(uniqueId, NULL);
+ sp<DrmManagerClientImpl> oldClient = setDrmManagerClientImpl(env, thiz, NULL);
+ if (oldClient != NULL) {
+ oldClient->setOnInfoListener(uniqueId, NULL);
+ }
}
-
LOGV("unload plugins - Exit");
+ return result;
}
static jobject android_drm_DrmManagerClient_getConstraintsFromContent(
@@ -356,10 +359,11 @@
LOGV("installDrmEngine - Exit");
}
-static void android_drm_DrmManagerClient_saveRights(
+static jint android_drm_DrmManagerClient_saveRights(
JNIEnv* env, jobject thiz, jint uniqueId,
jobject drmRights, jstring rightsPath, jstring contentPath) {
LOGV("saveRights - Enter");
+ int result = DRM_ERROR_UNKNOWN;
int dataLength = 0;
char* mData = Utility::getByteArrayValue(env, drmRights, "mData", &dataLength);
@@ -368,13 +372,14 @@
Utility::getStringValue(env, drmRights, "mMimeType"),
Utility::getStringValue(env, drmRights, "mAccountId"),
Utility::getStringValue(env, drmRights, "mSubscriptionId"));
- getDrmManagerClientImpl(env, thiz)
+ result = getDrmManagerClientImpl(env, thiz)
->saveRights(uniqueId, rights, Utility::getStringValue(env, rightsPath),
Utility::getStringValue(env, contentPath));
}
delete mData; mData = NULL;
LOGV("saveRights - Exit");
+ return result;
}
static jboolean android_drm_DrmManagerClient_canHandle(
@@ -423,7 +428,7 @@
String8 keyString = Utility::getStringValue(env, key);
String8 valueString = Utility::getStringValue(env, valString);
- LOGD("Key: %s | Value: %s", keyString.string(), valueString.string());
+ LOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
drmInfo.put(keyString, valueString);
}
@@ -495,7 +500,7 @@
String8 keyString = Utility::getStringValue(env, key);
String8 valueString = Utility::getStringValue(env, value);
- LOGD("Key: %s | Value: %s", keyString.string(), valueString.string());
+ LOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
drmInfoReq.put(keyString, valueString);
}
@@ -570,18 +575,17 @@
return rightsStatus;
}
-static void android_drm_DrmManagerClient_removeRights(
+static jint android_drm_DrmManagerClient_removeRights(
JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
- LOGV("removeRights Enter");
- getDrmManagerClientImpl(env, thiz)->removeRights(uniqueId, Utility::getStringValue(env, path));
- LOGV("removeRights Exit");
+ LOGV("removeRights");
+ return getDrmManagerClientImpl(env, thiz)
+ ->removeRights(uniqueId, Utility::getStringValue(env, path));
}
-static void android_drm_DrmManagerClient_removeAllRights(
+static jint android_drm_DrmManagerClient_removeAllRights(
JNIEnv* env, jobject thiz, jint uniqueId) {
- LOGV("removeAllRights Enter");
- getDrmManagerClientImpl(env, thiz)->removeAllRights(uniqueId);
- LOGV("removeAllRights Exit");
+ LOGV("removeAllRights");
+ return getDrmManagerClientImpl(env, thiz)->removeAllRights(uniqueId);
}
static jint android_drm_DrmManagerClient_openConvertSession(
@@ -674,10 +678,10 @@
static JNINativeMethod nativeMethods[] = {
- {"_loadPlugIns", "(ILjava/lang/Object;)V",
+ {"_loadPlugIns", "(ILjava/lang/Object;)I",
(void*)android_drm_DrmManagerClient_loadPlugIns},
- {"_unloadPlugIns", "(I)V",
+ {"_unloadPlugIns", "(I)I",
(void*)android_drm_DrmManagerClient_unloadPlugIns},
{"_getConstraints", "(ILjava/lang/String;I)Landroid/content/ContentValues;",
@@ -698,7 +702,7 @@
{"_acquireDrmInfo", "(ILandroid/drm/DrmInfoRequest;)Landroid/drm/DrmInfo;",
(void*)android_drm_DrmManagerClient_acquireDrmInfo},
- {"_saveRights", "(ILandroid/drm/DrmRights;Ljava/lang/String;Ljava/lang/String;)V",
+ {"_saveRights", "(ILandroid/drm/DrmRights;Ljava/lang/String;Ljava/lang/String;)I",
(void*)android_drm_DrmManagerClient_saveRights},
{"_getDrmObjectType", "(ILjava/lang/String;Ljava/lang/String;)I",
@@ -710,10 +714,10 @@
{"_checkRightsStatus", "(ILjava/lang/String;I)I",
(void*)android_drm_DrmManagerClient_checkRightsStatus},
- {"_removeRights", "(ILjava/lang/String;)V",
+ {"_removeRights", "(ILjava/lang/String;)I",
(void*)android_drm_DrmManagerClient_removeRights},
- {"_removeAllRights", "(I)V",
+ {"_removeAllRights", "(I)I",
(void*)android_drm_DrmManagerClient_removeAllRights},
{"_openConvertSession", "(ILjava/lang/String;)I",
diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp
index 06c7c50..c996994 100644
--- a/drm/libdrmframework/DrmManagerClient.cpp
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
-#define LOG_TAG "DrmManagerClient(Native)"
-#include <utils/Log.h>
-
#include <utils/String8.h>
#include <binder/IServiceManager.h>
#include <drm/DrmManagerClient.h>
@@ -37,8 +33,8 @@
}
DrmManagerClient::~DrmManagerClient() {
- unloadPlugIns();
DrmManagerClientImpl::remove(mUniqueId);
+ unloadPlugIns();
delete mDrmManagerClientImpl; mDrmManagerClientImpl = NULL;
}
@@ -72,7 +68,7 @@
return mDrmManagerClientImpl->acquireDrmInfo(mUniqueId, drmInfoRequest);
}
-void DrmManagerClient::saveRights(
+status_t DrmManagerClient::saveRights(
const DrmRights& drmRights, const String8& rightsPath, const String8& contentPath) {
return mDrmManagerClientImpl->saveRights(mUniqueId, drmRights, rightsPath, contentPath);
}
@@ -89,13 +85,14 @@
return mDrmManagerClientImpl->checkRightsStatus(mUniqueId, path, action);
}
-void DrmManagerClient::consumeRights(DecryptHandle* decryptHandle, int action, bool reserve) {
- mDrmManagerClientImpl->consumeRights(mUniqueId, decryptHandle, action, reserve);
+status_t DrmManagerClient::consumeRights(DecryptHandle* decryptHandle, int action, bool reserve) {
+ return mDrmManagerClientImpl->consumeRights(mUniqueId, decryptHandle, action, reserve);
}
-void DrmManagerClient::setPlaybackStatus(
+status_t DrmManagerClient::setPlaybackStatus(
DecryptHandle* decryptHandle, int playbackStatus, int position) {
- mDrmManagerClientImpl->setPlaybackStatus(mUniqueId, decryptHandle, playbackStatus, position);
+ return mDrmManagerClientImpl
+ ->setPlaybackStatus(mUniqueId, decryptHandle, playbackStatus, position);
}
bool DrmManagerClient::validateAction(
@@ -103,12 +100,12 @@
return mDrmManagerClientImpl->validateAction(mUniqueId, path, action, description);
}
-void DrmManagerClient::removeRights(const String8& path) {
- mDrmManagerClientImpl->removeRights(mUniqueId, path);
+status_t DrmManagerClient::removeRights(const String8& path) {
+ return mDrmManagerClientImpl->removeRights(mUniqueId, path);
}
-void DrmManagerClient::removeAllRights() {
- mDrmManagerClientImpl->removeAllRights(mUniqueId);
+status_t DrmManagerClient::removeAllRights() {
+ return mDrmManagerClientImpl->removeAllRights(mUniqueId);
}
int DrmManagerClient::openConvertSession(const String8& mimeType) {
@@ -131,25 +128,25 @@
return mDrmManagerClientImpl->openDecryptSession(mUniqueId, fd, offset, length);
}
-void DrmManagerClient::closeDecryptSession(DecryptHandle* decryptHandle) {
- mDrmManagerClientImpl->closeDecryptSession(mUniqueId, decryptHandle);
+status_t DrmManagerClient::closeDecryptSession(DecryptHandle* decryptHandle) {
+ return mDrmManagerClientImpl->closeDecryptSession(mUniqueId, decryptHandle);
}
-void DrmManagerClient::initializeDecryptUnit(
+status_t DrmManagerClient::initializeDecryptUnit(
DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
- mDrmManagerClientImpl->initializeDecryptUnit(
- mUniqueId, decryptHandle, decryptUnitId, headerInfo);
+ return mDrmManagerClientImpl->initializeDecryptUnit(
+ mUniqueId, decryptHandle, decryptUnitId, headerInfo);
}
status_t DrmManagerClient::decrypt(
DecryptHandle* decryptHandle, int decryptUnitId,
- const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
return mDrmManagerClientImpl->decrypt(
- mUniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+ mUniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
}
-void DrmManagerClient::finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId) {
- mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId, decryptHandle, decryptUnitId);
+status_t DrmManagerClient::finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId) {
+ return mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId, decryptHandle, decryptUnitId);
}
ssize_t DrmManagerClient::pread(
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index 7274b49..272adcd 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "DrmManagerClientImpl(Native)"
#include <utils/Log.h>
@@ -29,44 +29,21 @@
#define INVALID_VALUE -1
Mutex DrmManagerClientImpl::mMutex;
-Vector<int> DrmManagerClientImpl::mUniqueIdVector;
sp<IDrmManagerService> DrmManagerClientImpl::mDrmManagerService;
const String8 DrmManagerClientImpl::EMPTY_STRING("");
DrmManagerClientImpl* DrmManagerClientImpl::create(int* pUniqueId) {
if (0 == *pUniqueId) {
- int uniqueId = 0;
- bool foundUniqueId = false;
- srand(time(NULL));
-
- while (!foundUniqueId) {
- const int size = mUniqueIdVector.size();
- uniqueId = rand() % 100;
-
- int index = 0;
- for (; index < size; ++index) {
- if (mUniqueIdVector.itemAt(index) == uniqueId) {
- foundUniqueId = false;
- break;
- }
- }
- if (index == size) {
- foundUniqueId = true;
- }
- }
+ int uniqueId = getDrmManagerService()->addUniqueId(*pUniqueId);
*pUniqueId = uniqueId;
+ } else {
+ getDrmManagerService()->addUniqueId(*pUniqueId);
}
- mUniqueIdVector.push(*pUniqueId);
return new DrmManagerClientImpl();
}
void DrmManagerClientImpl::remove(int uniqueId) {
- for (int i = 0; i < mUniqueIdVector.size(); i++) {
- if (uniqueId == mUniqueIdVector.itemAt(i)) {
- mUniqueIdVector.removeAt(i);
- break;
- }
- }
+ getDrmManagerService()->removeUniqueId(uniqueId);
}
DrmManagerClientImpl::DrmManagerClientImpl() {
@@ -164,11 +141,13 @@
return drmInfo;
}
-void DrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights,
+status_t DrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
+ status_t status = DRM_ERROR_UNKNOWN;
if (EMPTY_STRING != contentPath) {
- getDrmManagerService()->saveRights(uniqueId, drmRights, rightsPath, contentPath);
+ status = getDrmManagerService()->saveRights(uniqueId, drmRights, rightsPath, contentPath);
}
+ return status;
}
String8 DrmManagerClientImpl::getOriginalMimeType(int uniqueId, const String8& path) {
@@ -197,19 +176,23 @@
return rightsStatus;
}
-void DrmManagerClientImpl::consumeRights(
+status_t DrmManagerClientImpl::consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ status_t status = DRM_ERROR_UNKNOWN;
if (NULL != decryptHandle) {
- getDrmManagerService()->consumeRights(uniqueId, decryptHandle, action, reserve);
+ status = getDrmManagerService()->consumeRights(uniqueId, decryptHandle, action, reserve);
}
+ return status;
}
-void DrmManagerClientImpl::setPlaybackStatus(
+status_t DrmManagerClientImpl::setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) {
+ status_t status = DRM_ERROR_UNKNOWN;
if (NULL != decryptHandle) {
- getDrmManagerService()->setPlaybackStatus(
+ status = getDrmManagerService()->setPlaybackStatus(
uniqueId, decryptHandle, playbackStatus, position);
}
+ return status;
}
bool DrmManagerClientImpl::validateAction(
@@ -221,14 +204,16 @@
return retCode;
}
-void DrmManagerClientImpl::removeRights(int uniqueId, const String8& path) {
+status_t DrmManagerClientImpl::removeRights(int uniqueId, const String8& path) {
+ status_t status = DRM_ERROR_UNKNOWN;
if (EMPTY_STRING != path) {
- getDrmManagerService()->removeRights(uniqueId, path);
+ status = getDrmManagerService()->removeRights(uniqueId, path);
}
+ return status;
}
-void DrmManagerClientImpl::removeAllRights(int uniqueId) {
- getDrmManagerService()->removeAllRights(uniqueId);
+status_t DrmManagerClientImpl::removeAllRights(int uniqueId) {
+ return getDrmManagerService()->removeAllRights(uniqueId);
}
int DrmManagerClientImpl::openConvertSession(int uniqueId, const String8& mimeType) {
@@ -263,40 +248,46 @@
DecryptHandle* DrmManagerClientImpl::openDecryptSession(
int uniqueId, int fd, int offset, int length) {
- LOGV("Entering DrmManagerClientImpl::openDecryptSession");
return getDrmManagerService()->openDecryptSession(uniqueId, fd, offset, length);
}
-void DrmManagerClientImpl::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
- if (NULL != decryptHandle) {
- getDrmManagerService()->closeDecryptSession( uniqueId, decryptHandle);
- }
-}
-
-void DrmManagerClientImpl::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* headerInfo) {
- if ((NULL != decryptHandle) && (NULL != headerInfo)) {
- getDrmManagerService()->initializeDecryptUnit(
- uniqueId, decryptHandle, decryptUnitId, headerInfo);
- }
-}
-
-status_t DrmManagerClientImpl::decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+status_t DrmManagerClientImpl::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
status_t status = DRM_ERROR_UNKNOWN;
- if ((NULL != decryptHandle) && (NULL != encBuffer)
- && (NULL != decBuffer) && (NULL != *decBuffer)) {
- status = getDrmManagerService()->decrypt(
- uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer);
+ if (NULL != decryptHandle) {
+ status = getDrmManagerService()->closeDecryptSession( uniqueId, decryptHandle);
}
return status;
}
-void DrmManagerClientImpl::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
- if (NULL != decryptHandle) {
- getDrmManagerService()->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+status_t DrmManagerClientImpl::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ int decryptUnitId, const DrmBuffer* headerInfo) {
+ status_t status = DRM_ERROR_UNKNOWN;
+ if ((NULL != decryptHandle) && (NULL != headerInfo)) {
+ status = getDrmManagerService()->initializeDecryptUnit(
+ uniqueId, decryptHandle, decryptUnitId, headerInfo);
}
+ return status;
+}
+
+status_t DrmManagerClientImpl::decrypt(int uniqueId, DecryptHandle* decryptHandle,
+ int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+ status_t status = DRM_ERROR_UNKNOWN;
+ if ((NULL != decryptHandle) && (NULL != encBuffer)
+ && (NULL != decBuffer) && (NULL != *decBuffer)) {
+ status = getDrmManagerService()->decrypt(
+ uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
+ }
+ return status;
+}
+
+status_t DrmManagerClientImpl::finalizeDecryptUnit(
+ int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ status_t status = DRM_ERROR_UNKNOWN;
+ if (NULL != decryptHandle) {
+ status
+ = getDrmManagerService()->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
+ }
+ return status;
}
ssize_t DrmManagerClientImpl::pread(int uniqueId, DecryptHandle* decryptHandle,
diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/libdrmframework/include/DrmManager.h
index 2ba9e99..dc3e460 100644
--- a/drm/libdrmframework/include/DrmManager.h
+++ b/drm/libdrmframework/include/DrmManager.h
@@ -53,6 +53,9 @@
virtual ~DrmManager();
public:
+ int addUniqueId(int uniqueId);
+
+ void removeUniqueId(int uniqueId);
status_t loadPlugIns(int uniqueId);
@@ -73,7 +76,7 @@
DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
- void saveRights(int uniqueId, const DrmRights& drmRights,
+ status_t saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath);
String8 getOriginalMimeType(int uniqueId, const String8& path);
@@ -82,17 +85,17 @@
int checkRightsStatus(int uniqueId, const String8& path, int action);
- void consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
- void setPlaybackStatus(
+ status_t setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
- void removeRights(int uniqueId, const String8& path);
+ status_t removeRights(int uniqueId, const String8& path);
- void removeAllRights(int uniqueId);
+ status_t removeAllRights(int uniqueId);
int openConvertSession(int uniqueId, const String8& mimeType);
@@ -104,15 +107,15 @@
DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length);
- void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
- void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer,DrmBuffer** decBuffer);
+ status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- void finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
void* buffer, ssize_t numBytes, off_t offset);
@@ -133,6 +136,7 @@
void initializePlugIns(int uniqueId);
private:
+ static Vector<int> mUniqueIdVector;
static const String8 EMPTY_STRING;
int mDecryptSessionId;
diff --git a/drm/libdrmframework/include/DrmManagerClientImpl.h b/drm/libdrmframework/include/DrmManagerClientImpl.h
index e70e6e1..492c7f5 100644
--- a/drm/libdrmframework/include/DrmManagerClientImpl.h
+++ b/drm/libdrmframework/include/DrmManagerClientImpl.h
@@ -132,8 +132,10 @@
* @param[in] drmRights DrmRights to be saved
* @param[in] rightsPath File path where rights to be saved
* @param[in] contentPath File path where content was saved
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void saveRights(int uniqueId, const DrmRights& drmRights,
+ status_t saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath);
/**
@@ -179,8 +181,10 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
* @param[in] reserve True if the rights should be reserved.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
/**
* Informs the DRM engine about the playback actions performed on the DRM files.
@@ -190,8 +194,10 @@
* @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
* @param[in] position Position in the file (in milliseconds) where the start occurs.
* Only valid together with Playback::START.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void setPlaybackStatus(
+ status_t setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
/**
@@ -211,16 +217,20 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] path Path of the protected content
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void removeRights(int uniqueId, const String8& path);
+ status_t removeRights(int uniqueId, const String8& path);
/**
* Removes all the rights information of each plug-in associated with
* DRM framework. Will be used in master reset
*
* @param[in] uniqueId Unique identifier for a session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void removeAllRights(int uniqueId);
+ status_t removeAllRights(int uniqueId);
/**
* This API is for Forward Lock based DRM scheme.
@@ -295,8 +305,10 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] decryptHandle Handle for the decryption session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
/**
* Initialize decryption for the given unit of the protected content
@@ -305,8 +317,10 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
* @param[in] headerInfo Information for initializing decryption of this decrypUnit
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
/**
@@ -319,14 +333,15 @@
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
* @param[in] encBuffer Encrypted data block
* @param[out] decBuffer Decrypted data block
+ * @param[in] IV Optional buffer
* @return status_t
* Returns the error code for this API
* DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+ status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
/**
* Finalize decryption for the given unit of the protected content
@@ -334,8 +349,10 @@
* @param[in] uniqueId Unique identifier for a session
* @param[in] decryptHandle Handle for the decryption session
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
/**
* Reads the specified number of bytes from an open DRM file.
@@ -388,7 +405,6 @@
private:
static Mutex mMutex;
- static Vector<int> mUniqueIdVector;
static sp<IDrmManagerService> mDrmManagerService;
static const sp<IDrmManagerService>& getDrmManagerService();
static const String8 EMPTY_STRING;
diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/libdrmframework/include/DrmManagerService.h
index fef121c..f455e15 100644
--- a/drm/libdrmframework/include/DrmManagerService.h
+++ b/drm/libdrmframework/include/DrmManagerService.h
@@ -46,6 +46,10 @@
virtual ~DrmManagerService();
public:
+ int addUniqueId(int uniqueId);
+
+ void removeUniqueId(int uniqueId);
+
status_t loadPlugIns(int uniqueId);
status_t loadPlugIns(int uniqueId, const String8& plugInDirPath);
@@ -65,7 +69,7 @@
DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest);
- void saveRights(int uniqueId, const DrmRights& drmRights,
+ status_t saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath);
String8 getOriginalMimeType(int uniqueId, const String8& path);
@@ -74,17 +78,17 @@
int checkRightsStatus(int uniqueId, const String8& path,int action);
- void consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
- void setPlaybackStatus(
+ status_t setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
bool validateAction(int uniqueId, const String8& path,
int action, const ActionDescription& description);
- void removeRights(int uniqueId, const String8& path);
+ status_t removeRights(int uniqueId, const String8& path);
- void removeAllRights(int uniqueId);
+ status_t removeAllRights(int uniqueId);
int openConvertSession(int uniqueId, const String8& mimeType);
@@ -96,15 +100,15 @@
DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length);
- void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
- void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+ status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- void finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
void* buffer, ssize_t numBytes, off_t offset);
diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/libdrmframework/include/IDrmManagerService.h
index a4d128a..5c668ed 100644
--- a/drm/libdrmframework/include/IDrmManagerService.h
+++ b/drm/libdrmframework/include/IDrmManagerService.h
@@ -44,7 +44,9 @@
{
public:
enum {
- LOAD_PLUGINS = IBinder::FIRST_CALL_TRANSACTION,
+ ADD_UNIQUEID = IBinder::FIRST_CALL_TRANSACTION,
+ REMOVE_UNIQUEID,
+ LOAD_PLUGINS,
LOAD_PLUGINS_FROM_PATH,
SET_DRM_SERVICE_LISTENER,
UNLOAD_PLUGINS,
@@ -78,6 +80,10 @@
DECLARE_META_INTERFACE(DrmManagerService);
public:
+ virtual int addUniqueId(int uniqueId) = 0;
+
+ virtual void removeUniqueId(int uniqueId) = 0;
+
virtual status_t loadPlugIns(int uniqueId) = 0;
virtual status_t loadPlugIns(int uniqueId, const String8& plugInDirPath) = 0;
@@ -98,7 +104,7 @@
virtual DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest) = 0;
- virtual void saveRights(int uniqueId, const DrmRights& drmRights,
+ virtual status_t saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) = 0;
virtual String8 getOriginalMimeType(int uniqueId, const String8& path) = 0;
@@ -108,19 +114,19 @@
virtual int checkRightsStatus(int uniqueId, const String8& path, int action) = 0;
- virtual void consumeRights(
+ virtual status_t consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
- virtual void setPlaybackStatus(
+ virtual status_t setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) = 0;
virtual bool validateAction(
int uniqueId, const String8& path,
int action, const ActionDescription& description) = 0;
- virtual void removeRights(int uniqueId, const String8& path) = 0;
+ virtual status_t removeRights(int uniqueId, const String8& path) = 0;
- virtual void removeAllRights(int uniqueId) = 0;
+ virtual status_t removeAllRights(int uniqueId) = 0;
virtual int openConvertSession(int uniqueId, const String8& mimeType) = 0;
@@ -134,15 +140,15 @@
virtual DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length) = 0;
- virtual void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
- virtual void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) = 0;
+ virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
- virtual void finalizeDecryptUnit(
+ virtual status_t finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
@@ -158,6 +164,10 @@
BpDrmManagerService(const sp<IBinder>& impl)
: BpInterface<IDrmManagerService>(impl) {}
+ virtual int addUniqueId(int uniqueId);
+
+ virtual void removeUniqueId(int uniqueId);
+
virtual status_t loadPlugIns(int uniqueId);
virtual status_t loadPlugIns(int uniqueId, const String8& plugInDirPath);
@@ -177,7 +187,7 @@
virtual DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInforequest);
- virtual void saveRights(int uniqueId, const DrmRights& drmRights,
+ virtual status_t saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath);
virtual String8 getOriginalMimeType(int uniqueId, const String8& path);
@@ -186,18 +196,18 @@
virtual int checkRightsStatus(int uniqueId, const String8& path, int action);
- virtual void consumeRights(
+ virtual status_t consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
- virtual void setPlaybackStatus(
+ virtual status_t setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
virtual bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
- virtual void removeRights(int uniqueId, const String8& path);
+ virtual status_t removeRights(int uniqueId, const String8& path);
- virtual void removeAllRights(int uniqueId);
+ virtual status_t removeAllRights(int uniqueId);
virtual int openConvertSession(int uniqueId, const String8& mimeType);
@@ -211,15 +221,15 @@
virtual DecryptHandle* openDecryptSession(int uniqueId, int fd, int offset, int length);
- virtual void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
- virtual void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+ virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- virtual void finalizeDecryptUnit(
+ virtual status_t finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
diff --git a/drm/libdrmframework/include/ReadWriteUtils.h b/drm/libdrmframework/include/ReadWriteUtils.h
index 022149ee2..529b342 100644
--- a/drm/libdrmframework/include/ReadWriteUtils.h
+++ b/drm/libdrmframework/include/ReadWriteUtils.h
@@ -47,6 +47,14 @@
*/
static String8 readBytes(const String8& filePath);
/**
+ * Reads the data into the given buffer from the file path provided
+ *
+ * @param[in] filePath Path of the file
+ * @param[out] buffer Data read from the file
+ * @return Length of the data read from the file
+ */
+ static int readBytes(const String8& filePath, char** buffer);
+ /**
* Writes the data into the file path provided
*
* @param[in] filePath Path of the file
diff --git a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
index 667958a..b355534 100644
--- a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
+++ b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
@@ -46,7 +46,7 @@
DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
- void saveRights(int uniqueId, const DrmRights& drmRights,
+ status_t saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath);
DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
@@ -57,19 +57,19 @@
int checkRightsStatus(int uniqueId, const String8& path, int action);
- void consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
- void setPlaybackStatus(
+ status_t setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
- void removeRights(int uniqueId, const String8& path);
+ status_t removeRights(int uniqueId, const String8& path);
- void removeAllRights(int uniqueId);
+ status_t removeAllRights(int uniqueId);
- void openConvertSession(int uniqueId, int convertId);
+ status_t openConvertSession(int uniqueId, int convertId);
DrmConvertedStatus* convertData(int uniqueId, int convertId, const DrmBuffer* inputData);
@@ -80,15 +80,15 @@
status_t openDecryptSession(
int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length);
- void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
- void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+ status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- void finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
void* buffer, ssize_t numBytes, off_t offset);
@@ -172,8 +172,10 @@
* @param[in] drmRights DrmRights to be saved
* @param[in] rightsPath File path where rights to be saved
* @param[in] contentPath File path where content was saved
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onSaveRights(int uniqueId, const DrmRights& drmRights,
+ virtual status_t onSaveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightspath, const String8& contentPath) = 0;
/**
@@ -231,8 +233,10 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
* @param[in] reserve True if the rights should be reserved.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
int action, bool reserve) = 0;
/**
@@ -243,8 +247,10 @@
* @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
* @param[in] position Position in the file (in milliseconds) where the start occurs.
* Only valid together with Playback::START.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onSetPlaybackStatus(
+ virtual status_t onSetPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position) = 0;
/**
@@ -264,16 +270,20 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] path Path of the protected content
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onRemoveRights(int uniqueId, const String8& path) = 0;
+ virtual status_t onRemoveRights(int uniqueId, const String8& path) = 0;
/**
* Removes all the rights information of each plug-in associated with
* DRM framework. Will be used in master reset
*
* @param[in] uniqueId Unique identifier for a session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onRemoveAllRights(int uniqueId) = 0;
+ virtual status_t onRemoveAllRights(int uniqueId) = 0;
/**
* This API is for Forward Lock based DRM scheme.
@@ -283,8 +293,10 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] convertId Handle for the convert session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onOpenConvertSession(int uniqueId, int convertId) = 0;
+ virtual status_t onOpenConvertSession(int uniqueId, int convertId) = 0;
/**
* Accepts and converts the input data which is part of DRM file.
@@ -347,8 +359,10 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] decryptHandle Handle for the decryption session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
/**
* Initialize decryption for the given unit of the protected content
@@ -357,8 +371,10 @@
* @param[in] decryptId Handle for the decryption session
* @param[in] decryptUnitId ID Specifies decryption unit, such as track ID
* @param[in] headerInfo Information for initializing decryption of this decrypUnit
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
/**
@@ -371,14 +387,15 @@
* @param[in] decryptUnitId ID Specifies decryption unit, such as track ID
* @param[in] encBuffer Encrypted data block
* @param[out] decBuffer Decrypted data block
+ * @param[in] IV Optional buffer
* @return status_t
* Returns the error code for this API
* DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
- virtual status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) = 0;
+ virtual status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
/**
* Finalize decryption for the given unit of the protected content
@@ -386,8 +403,10 @@
* @param[in] uniqueId Unique identifier for a session
* @param[in] decryptHandle Handle for the decryption session
* @param[in] decryptUnitId ID Specifies decryption unit, such as track ID
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void onFinalizeDecryptUnit(
+ virtual status_t onFinalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
/**
diff --git a/drm/libdrmframework/plugins/common/include/IDrmEngine.h b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
index 0d52f66..b711500 100644
--- a/drm/libdrmframework/plugins/common/include/IDrmEngine.h
+++ b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
@@ -143,8 +143,10 @@
* @param[in] drmRights DrmRights to be saved
* @param[in] rightsPath File path where rights to be saved
* @param[in] contentPath File path where content was saved
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void saveRights(int uniqueId, const DrmRights& drmRights,
+ virtual status_t saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) = 0;
/**
@@ -191,8 +193,10 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
* @param[in] reserve True if the rights should be reserved.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void consumeRights(
+ virtual status_t consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
/**
@@ -203,8 +207,10 @@
* @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
* @param[in] position Position in the file (in milliseconds) where the start occurs.
* Only valid together with Playback::START.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void setPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t setPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
int playbackStatus, int position) = 0;
/**
@@ -224,16 +230,20 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] path Path of the protected content
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void removeRights(int uniqueId, const String8& path) = 0;
+ virtual status_t removeRights(int uniqueId, const String8& path) = 0;
/**
* Removes all the rights information of each plug-in associated with
* DRM framework. Will be used in master reset
*
* @param[in] uniqueId Unique identifier for a session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void removeAllRights(int uniqueId) = 0;
+ virtual status_t removeAllRights(int uniqueId) = 0;
/**
* This API is for Forward Lock based DRM scheme.
@@ -243,8 +253,10 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] convertId Handle for the convert session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void openConvertSession(int uniqueId, int convertId) = 0;
+ virtual status_t openConvertSession(int uniqueId, int convertId) = 0;
/**
* Accepts and converts the input data which is part of DRM file.
@@ -307,8 +319,10 @@
*
* @param[in] uniqueId Unique identifier for a session
* @param[in] decryptHandle Handle for the decryption session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
/**
* Initialize decryption for the given unit of the protected content
@@ -317,8 +331,10 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
* @param[in] headerInfo Information for initializing decryption of this decrypUnit
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
/**
@@ -331,14 +347,15 @@
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
* @param[in] encBuffer Encrypted data block
* @param[out] decBuffer Decrypted data block
+ * @param[in] IV Optional buffer
* @return status_t
* Returns the error code for this API
* DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) = 0;
+ virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
/**
* Finalize decryption for the given unit of the protected content
@@ -346,8 +363,10 @@
* @param[in] uniqueId Unique identifier for a session
* @param[in] decryptHandle Handle for the decryption session
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual void finalizeDecryptUnit(
+ virtual status_t finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
/**
diff --git a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
index d2c7852..eed1628 100644
--- a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
+++ b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
@@ -40,7 +40,7 @@
DrmInfoStatus* onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo);
- void onSaveRights(int uniqueId, const DrmRights& drmRights,
+ status_t onSaveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath);
DrmInfo* onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
@@ -51,19 +51,19 @@
int onCheckRightsStatus(int uniqueId, const String8& path, int action);
- void onConsumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
- void onSetPlaybackStatus(
+ status_t onSetPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int position);
bool onValidateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
- void onRemoveRights(int uniqueId, const String8& path);
+ status_t onRemoveRights(int uniqueId, const String8& path);
- void onRemoveAllRights(int uniqueId);
+ status_t onRemoveAllRights(int uniqueId);
- void onOpenConvertSession(int uniqueId, int convertId);
+ status_t onOpenConvertSession(int uniqueId, int convertId);
DrmConvertedStatus* onConvertData(int uniqueId, int convertId, const DrmBuffer* inputData);
@@ -74,15 +74,15 @@
status_t onOpenDecryptSession(
int uniqueId, DecryptHandle* decryptHandle, int fd, int offset, int length);
- void onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
- void onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+ status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- void onFinalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t onFinalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
void* buffer, ssize_t numBytes, off_t offset);
diff --git a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
index 2655d0b..4c7714d 100644
--- a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
+++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
@@ -129,9 +129,10 @@
return drmSupportInfo;
}
-void DrmPassthruPlugIn::onSaveRights(int uniqueId, const DrmRights& drmRights,
+status_t DrmPassthruPlugIn::onSaveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
LOGD("DrmPassthruPlugIn::onSaveRights : %d", uniqueId);
+ return DRM_NO_ERROR;
}
DrmInfo* DrmPassthruPlugIn::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
@@ -174,14 +175,16 @@
return rightsStatus;
}
-void DrmPassthruPlugIn::onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmPassthruPlugIn::onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
int action, bool reserve) {
LOGD("DrmPassthruPlugIn::onConsumeRights() : %d", uniqueId);
+ return DRM_NO_ERROR;
}
-void DrmPassthruPlugIn::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmPassthruPlugIn::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
int playbackStatus, int position) {
LOGD("DrmPassthruPlugIn::onSetPlaybackStatus() : %d", uniqueId);
+ return DRM_NO_ERROR;
}
bool DrmPassthruPlugIn::onValidateAction(int uniqueId, const String8& path,
@@ -190,16 +193,19 @@
return true;
}
-void DrmPassthruPlugIn::onRemoveRights(int uniqueId, const String8& path) {
+status_t DrmPassthruPlugIn::onRemoveRights(int uniqueId, const String8& path) {
LOGD("DrmPassthruPlugIn::onRemoveRights() : %d", uniqueId);
+ return DRM_NO_ERROR;
}
-void DrmPassthruPlugIn::onRemoveAllRights(int uniqueId) {
+status_t DrmPassthruPlugIn::onRemoveAllRights(int uniqueId) {
LOGD("DrmPassthruPlugIn::onRemoveAllRights() : %d", uniqueId);
+ return DRM_NO_ERROR;
}
-void DrmPassthruPlugIn::onOpenConvertSession(int uniqueId, int convertId) {
+status_t DrmPassthruPlugIn::onOpenConvertSession(int uniqueId, int convertId) {
LOGD("DrmPassthruPlugIn::onOpenConvertSession() : %d", uniqueId);
+ return DRM_NO_ERROR;
}
DrmConvertedStatus* DrmPassthruPlugIn::onConvertData(
@@ -237,7 +243,7 @@
return DRM_ERROR_CANNOT_HANDLE;
}
-void DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
LOGD("DrmPassthruPlugIn::onCloseDecryptSession() : %d", uniqueId);
if (NULL != decryptHandle) {
if (NULL != decryptHandle->decryptInfo) {
@@ -245,15 +251,17 @@
}
delete decryptHandle; decryptHandle = NULL;
}
+ return DRM_NO_ERROR;
}
-void DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
LOGD("DrmPassthruPlugIn::onInitializeDecryptUnit() : %d", uniqueId);
+ return DRM_NO_ERROR;
}
status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
- int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer) {
+ int decryptUnitId, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
LOGD("DrmPassthruPlugIn::onDecrypt() : %d", uniqueId);
/**
* As a workaround implementation passthru would copy the given
@@ -267,9 +275,10 @@
return DRM_NO_ERROR;
}
-void DrmPassthruPlugIn::onFinalizeDecryptUnit(
+status_t DrmPassthruPlugIn::onFinalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
LOGD("DrmPassthruPlugIn::onFinalizeDecryptUnit() : %d", uniqueId);
+ return DRM_NO_ERROR;
}
ssize_t DrmPassthruPlugIn::onPread(int uniqueId, DecryptHandle* decryptHandle,
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index 5e8817c..c722bd3 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -27,28 +27,40 @@
*/
class DrmInfoEvent {
public:
+ /**
+ * The following constant values should be in sync with DrmInfoEvent.java
+ */
//! TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT, when registration has been
//! already done by another account ID.
- static const int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 0x0000001;
+ static const int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1;
//! TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely.
- static const int TYPE_REMOVE_RIGHTS = 0x0000002;
+ static const int TYPE_REMOVE_RIGHTS = 2;
//! TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok.
- static const int TYPE_RIGHTS_INSTALLED = 0x0000003;
- //! TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights
- static const int TYPE_RIGHTS_NOT_INSTALLED = 0x0000004;
- //! TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights
- static const int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 0x0000005;
- //! TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent
- static const int TYPE_NOT_SUPPORTED = 0x0000006;
+ static const int TYPE_RIGHTS_INSTALLED = 3;
//! TYPE_WAIT_FOR_RIGHTS, rights object is on it's way to phone,
//! wait before calling checkRights again
- static const int TYPE_WAIT_FOR_RIGHTS = 0x0000007;
+ static const int TYPE_WAIT_FOR_RIGHTS = 4;
+ //! TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
+ //! already done for the given account.
+ static const int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
+
+ /**
+ * The following constant values should be in sync with DrmErrorEvent.java
+ */
+ //! TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights
+ static const int TYPE_RIGHTS_NOT_INSTALLED = 2001;
+ //! TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights
+ static const int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002;
+ //! TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent
+ static const int TYPE_NOT_SUPPORTED = 2003;
//! TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal.
//! Can in the future perhaps be used to trigger garbage collector
- static const int TYPE_OUT_OF_MEMORY = 0x0000008;
+ static const int TYPE_OUT_OF_MEMORY = 2004;
//! TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt
//! can be made to renew rights
- static const int TYPE_NO_INTERNET_CONNECTION = 0x0000009;
+ static const int TYPE_NO_INTERNET_CONNECTION = 2005;
+ //! TYPE_REGISTRATION_FAILED, when registration with server failed.
+ static const int TYPE_REGISTRATION_FAILED = 2006;
public:
/**
diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h
index 7d14c44..c2ad084 100644
--- a/include/drm/DrmManagerClient.h
+++ b/include/drm/DrmManagerClient.h
@@ -70,8 +70,10 @@
* Close the decrypt session for the given handle
*
* @param[in] decryptHandle Handle for the decryption session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void closeDecryptSession(DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(DecryptHandle* decryptHandle);
/**
* Consumes the rights for a content.
@@ -81,8 +83,11 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
* @param[in] reserve True if the rights should be reserved.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure.
+ * In case license has been expired, DRM_ERROR_LICENSE_EXPIRED will be returned.
*/
- void consumeRights(DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(DecryptHandle* decryptHandle, int action, bool reserve);
/**
* Informs the DRM engine about the playback actions performed on the DRM files.
@@ -90,9 +95,11 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
* @param[in] position Position in the file (in milliseconds) where the start occurs.
- * Only valid together with Playback::START.
+ * Only valid together with Playback::START.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void setPlaybackStatus(DecryptHandle* decryptHandle, int playbackStatus, int position);
+ status_t setPlaybackStatus(DecryptHandle* decryptHandle, int playbackStatus, int position);
/**
* Initialize decryption for the given unit of the protected content
@@ -100,8 +107,10 @@
* @param[in] decryptHandle Handle for the decryption session
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
* @param[in] headerInfo Information for initializing decryption of this decrypUnit
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void initializeDecryptUnit(
+ status_t initializeDecryptUnit(
DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo);
/**
@@ -113,6 +122,7 @@
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
* @param[in] encBuffer Encrypted data block
* @param[out] decBuffer Decrypted data block
+ * @param[in] IV Optional buffer
* @return status_t
* Returns the error code for this API
* DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
@@ -121,15 +131,17 @@
*/
status_t decrypt(
DecryptHandle* decryptHandle, int decryptUnitId,
- const DrmBuffer* encBuffer, DrmBuffer** decBuffer);
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV = NULL);
/**
* Finalize decryption for the given unit of the protected content
*
* @param[in] decryptHandle Handle for the decryption session
* @param[in] decryptUnitId ID which specifies decryption unit, such as track ID
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId);
/**
* Reads the specified number of bytes from an open DRM file.
@@ -217,8 +229,10 @@
* @param[in] drmRights DrmRights to be saved
* @param[in] rightsPath File path where rights to be saved
* @param[in] contentPath File path where content was saved
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void saveRights(
+ status_t saveRights(
const DrmRights& drmRights, const String8& rightsPath, const String8& contentPath);
/**
@@ -256,15 +270,19 @@
* Removes the rights associated with the given protected content
*
* @param[in] path Path of the protected content
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void removeRights(const String8& path);
+ status_t removeRights(const String8& path);
/**
* Removes all the rights information of each plug-in associated with
* DRM framework. Will be used in master reset
*
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- void removeAllRights();
+ status_t removeAllRights();
/**
* This API is for Forward Lock DRM.
diff --git a/include/drm/DrmRights.h b/include/drm/DrmRights.h
index e04a066..11f8f78 100644
--- a/include/drm/DrmRights.h
+++ b/include/drm/DrmRights.h
@@ -61,7 +61,7 @@
/**
* Destructor for DrmRights
*/
- virtual ~DrmRights() {}
+ virtual ~DrmRights();
public:
/**
@@ -97,6 +97,7 @@
String8 mMimeType;
String8 mAccountId;
String8 mSubscriptionId;
+ char* mRightsFromFile;
};
};
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index 8b8a9f5..c5765a9 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -254,13 +254,13 @@
* (file format is not encrypted but ES is encrypted)
* e.g., Marlin DRM (MP4 file format), WM-DRM (asf file format)
*
- * DecryptAPI::TYPE_ELEMENTARY_STREAM_BASED
+ * DecryptApiType::ELEMENTARY_STREAM_BASED
* Decryption API set for ES based DRM
* initializeDecryptUnit(), decrypt(), and finalizeDecryptUnit()
* 2. Decrypt APIs for container based DRM (file format itself is encrypted)
* e.g., OMA DRM (dcf file format)
*
- * DecryptAPI::TYPE_CONTAINER_BASED
+ * DecryptApiType::CONTAINER_BASED
* POSIX based Decryption API set for container based DRM
* pread()
*/
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index ed5f09f..3592aeb 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -20,25 +20,71 @@
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaSource.h>
+#include <camera/ICamera.h>
+#include <camera/CameraParameters.h>
#include <utils/List.h>
#include <utils/RefBase.h>
namespace android {
-class ICamera;
class IMemory;
class Camera;
+class Surface;
class CameraSource : public MediaSource, public MediaBufferObserver {
public:
+ /**
+ * Factory method to create a new CameraSource using the current
+ * settings (such as video size, frame rate, color format, etc)
+ * from the default camera.
+ *
+ * @return NULL on error.
+ */
static CameraSource *Create();
- static CameraSource *CreateFromCamera(const sp<Camera> &camera);
+
+ /**
+ * Factory method to create a new CameraSource.
+ *
+ * @param camera the video input frame data source. If it is NULL,
+ * we will try to connect to the camera with the given
+ * cameraId.
+ *
+ * @param cameraId the id of the camera that the source will connect
+ * to if camera is NULL; otherwise ignored.
+ *
+ * @param videoSize the dimension (in pixels) of the video frame
+ * @param frameRate the target frames per second
+ * @param surface the preview surface for display where preview
+ * frames are sent to
+ *
+ * @return NULL on error.
+ */
+ static CameraSource *CreateFromCamera(const sp<ICamera> &camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t frameRate,
+ const sp<Surface>& surface);
virtual ~CameraSource();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
+ /**
+ * Check whether a CameraSource object is properly initialized.
+ * Must call this method before stop().
+ * @return OK if initialization has successfully completed.
+ */
+ virtual status_t initCheck() const;
+
+ /**
+ * Returns the MetaData associated with the CameraSource,
+ * including:
+ * kKeyColorFormat: YUV color format of the video frames
+ * kKeyWidth, kKeyHeight: dimension (in pixels) of the video frames
+ * kKeySampleRate: frame rate in frames per second
+ * kKeyMIMEType: always fixed to be MEDIA_MIMETYPE_VIDEO_RAW
+ */
virtual sp<MetaData> getFormat();
virtual status_t read(
@@ -47,7 +93,19 @@
virtual void signalBufferReturned(MediaBuffer* buffer);
protected:
- sp<Camera> mCamera;
+ enum CameraFlags {
+ FLAGS_SET_CAMERA = 1L << 0,
+ FLAGS_HOT_CAMERA = 1L << 1,
+ };
+
+ int32_t mCameraFlags;
+ Size mVideoSize;
+ int32_t mVideoFrameRate;
+ int32_t mColorFormat;
+ status_t mInitCheck;
+
+ sp<Camera> mCamera;
+ sp<Surface> mSurface;
sp<MetaData> mMeta;
int64_t mStartTimeUs;
@@ -55,7 +113,9 @@
int64_t mLastFrameTimestampUs;
bool mStarted;
- CameraSource(const sp<Camera> &camera);
+ CameraSource(const sp<ICamera>& camera, int32_t cameraId,
+ Size videoSize, int32_t frameRate,
+ const sp<Surface>& surface);
virtual void startCameraRecording();
virtual void stopCameraRecording();
@@ -91,6 +151,21 @@
void releaseQueuedFrames();
void releaseOneRecordingFrame(const sp<IMemory>& frame);
+
+ status_t init(const sp<ICamera>& camera, int32_t cameraId,
+ Size videoSize, int32_t frameRate);
+ status_t isCameraAvailable(const sp<ICamera>& camera, int32_t cameraId);
+ status_t isCameraColorFormatSupported(const CameraParameters& params);
+ status_t configureCamera(CameraParameters* params,
+ int32_t width, int32_t height,
+ int32_t frameRate);
+
+ status_t checkVideoSize(const CameraParameters& params,
+ int32_t width, int32_t height);
+
+ status_t checkFrameRate(const CameraParameters& params,
+ int32_t frameRate);
+
CameraSource(const CameraSource &);
CameraSource &operator=(const CameraSource &);
};
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 3b303f8..afe7287 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -31,15 +31,13 @@
class CameraSourceTimeLapse : public CameraSource {
public:
- static CameraSourceTimeLapse *Create(
- int64_t timeBetweenTimeLapseFrameCaptureUs,
- int32_t width, int32_t height,
- int32_t videoFrameRate);
-
- static CameraSourceTimeLapse *CreateFromCamera(const sp<Camera> &camera,
- int64_t timeBetweenTimeLapseFrameCaptureUs,
- int32_t width, int32_t height,
- int32_t videoFrameRate);
+ static CameraSourceTimeLapse *CreateFromCamera(
+ const sp<ICamera> &camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t videoFrameRate,
+ const sp<Surface>& surface,
+ int64_t timeBetweenTimeLapseFrameCaptureUs);
virtual ~CameraSourceTimeLapse();
@@ -132,10 +130,13 @@
// Status code for last read.
status_t mLastReadStatus;
- CameraSourceTimeLapse(const sp<Camera> &camera,
- int64_t timeBetweenTimeLapseFrameCaptureUs,
- int32_t width, int32_t height,
- int32_t videoFrameRate);
+ CameraSourceTimeLapse(
+ const sp<ICamera> &camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t videoFrameRate,
+ const sp<Surface>& surface,
+ int64_t timeBetweenTimeLapseFrameCaptureUs);
// Wrapper over CameraSource::signalBufferReturned() to implement quick stop.
// It only handles the case when mLastReadBufferCopy is signalled. Otherwise
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 73d0f77..e44122d 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -39,6 +39,7 @@
// Not technically an error.
INFO_FORMAT_CHANGED = MEDIA_ERROR_BASE - 12,
+ INFO_DISCONTINUITY = MEDIA_ERROR_BASE - 13,
};
} // namespace android
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index ab2f11d..d2bd9f2 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -97,6 +97,8 @@
kKeyAutoLoop = 'autL', // bool (int32_t)
kKeyValidSamples = 'valD', // int32_t
+
+ kKeyIsUnreadable = 'unre', // bool (int32_t)
};
enum {
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 875bc5b..2bb7783 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -32,7 +32,8 @@
struct OMXCodec : public MediaSource,
public MediaBufferObserver {
enum CreationFlags {
- kPreferSoftwareCodecs = 1,
+ kPreferSoftwareCodecs = 1,
+ kIgnoreCodecSpecificData = 2
};
static sp<MediaSource> Create(
const sp<IOMX> &omx,
@@ -103,6 +104,7 @@
kSupportsMultipleFramesPerInputBuffer = 1024,
kAvoidMemcopyInputRecordingFrames = 2048,
kRequiresLargerEncoderOutputBuffer = 4096,
+ kOutputBuffersAreUnreadable = 8192,
};
struct BufferInfo {
@@ -247,9 +249,10 @@
void dumpPortStatus(OMX_U32 portIndex);
- status_t configureCodec(const sp<MetaData> &meta);
+ status_t configureCodec(const sp<MetaData> &meta, uint32_t flags);
- static uint32_t getComponentQuirks(const char *componentName);
+ static uint32_t getComponentQuirks(
+ const char *componentName, bool isEncoder);
static void findMatchingCodecs(
const char *mime,
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index 3f00b78..cc51490 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -20,9 +20,22 @@
#include <utils/threads.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>
+#include <utils/Timers.h>
#include <android/looper.h>
+// Currently using poll() instead of epoll_wait() since it does a better job of meeting a
+// timeout deadline. epoll_wait() typically causes additional delays of up to 10ms
+// beyond the requested timeout.
+//#define LOOPER_USES_EPOLL
+//#define LOOPER_STATISTICS
+
+#ifdef LOOPER_USES_EPOLL
+#include <sys/epoll.h>
+#else
+#include <sys/poll.h>
+#endif
+
/*
* Declare a concrete type for the NDK's looper forward declaration.
*/
@@ -190,13 +203,54 @@
const bool mAllowNonCallbacks; // immutable
- int mEpollFd; // immutable
int mWakeReadPipeFd; // immutable
int mWakeWritePipeFd; // immutable
+ Mutex mLock;
+
+#ifdef LOOPER_USES_EPOLL
+ int mEpollFd; // immutable
// Locked list of file descriptor monitoring requests.
- Mutex mLock;
- KeyedVector<int, Request> mRequests;
+ KeyedVector<int, Request> mRequests; // guarded by mLock
+#else
+ // The lock guards state used to track whether there is a poll() in progress and whether
+ // there are any other threads waiting in wakeAndLock(). The condition variables
+ // are used to transfer control among these threads such that all waiters are
+ // serviced before a new poll can begin.
+ // The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
+ // until mPolling becomes false, then decrements mWaiters again.
+ // The poll() method blocks on mResume until mWaiters becomes 0, then sets
+ // mPolling to true, blocks until the poll completes, then resets mPolling to false
+ // and signals mResume if there are waiters.
+ bool mPolling; // guarded by mLock
+ uint32_t mWaiters; // guarded by mLock
+ Condition mAwake; // guarded by mLock
+ Condition mResume; // guarded by mLock
+
+ Vector<struct pollfd> mRequestedFds; // must hold mLock and mPolling must be false to modify
+ Vector<Request> mRequests; // must hold mLock and mPolling must be false to modify
+
+ ssize_t getRequestIndexLocked(int fd);
+ void wakeAndLock();
+#endif
+
+#ifdef LOOPER_STATISTICS
+ static const int SAMPLED_WAKE_CYCLES_TO_AGGREGATE = 100;
+ static const int SAMPLED_POLLS_TO_AGGREGATE = 1000;
+
+ nsecs_t mPendingWakeTime;
+ int mPendingWakeCount;
+
+ int mSampledWakeCycles;
+ int mSampledWakeCountSum;
+ nsecs_t mSampledWakeLatencySum;
+
+ int mSampledPolls;
+ int mSampledZeroPollCount;
+ int mSampledZeroPollLatencySum;
+ int mSampledTimeoutPollCount;
+ int mSampledTimeoutPollLatencySum;
+#endif
// This state is only used privately by pollOnce and does not require a lock since
// it runs on a single thread.
@@ -204,6 +258,8 @@
size_t mResponseIndex;
int pollInner(int timeoutMillis);
+ void awoken();
+ void pushResponse(int events, const Request& request);
static void initTLSKey();
static void threadDestructor(void *st);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 43af702..437a9ef 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -5,6 +5,7 @@
# defined in the current device/board configuration
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SRC_FILES:= \
+ utils/SortedListImpl.cpp \
DisplayListRenderer.cpp \
FboCache.cpp \
FontRenderer.cpp \
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index c829fd4..48877f6 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -20,7 +20,7 @@
#include <SkShader.h>
#include "Texture.h"
-#include "GenerationCache.h"
+#include "utils/GenerationCache.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 6024765..2afe2fa 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -28,46 +28,33 @@
namespace android {
namespace uirenderer {
-/**
- * Dimensions of a layer.
- */
-struct LayerSize {
- LayerSize(): width(0), height(0) { }
- LayerSize(const uint32_t width, const uint32_t height): width(width), height(height) { }
- LayerSize(const LayerSize& size): width(size.width), height(size.height) { }
-
- uint32_t width;
- uint32_t height;
-
- bool operator<(const LayerSize& rhs) const {
- if (width == rhs.width) {
- return height < rhs.height;
- }
- return width < rhs.width;
- }
-
- bool operator==(const LayerSize& rhs) const {
- return width == rhs.width && height == rhs.height;
- }
-}; // struct LayerSize
+///////////////////////////////////////////////////////////////////////////////
+// Layers
+///////////////////////////////////////////////////////////////////////////////
/**
* A layer has dimensions and is backed by an OpenGL texture or FBO.
*/
struct Layer {
+ Layer(const uint32_t layerWidth, const uint32_t layerHeight):
+ width(layerWidth), height(layerHeight) {
+ }
+
/**
- * Coordinates of the layer.
+ * Bounds of the layer.
*/
Rect layer;
/**
- * Name of the texture used to render the layer.
+ * Texture coordinates of the layer.
*/
- GLuint texture;
+ Rect texCoords;
+
/**
* Name of the FBO used to render the layer. If the name is 0
* this layer is not backed by an FBO, but a simple texture.
*/
GLuint fbo;
+
/**
* Opacity of the layer.
*/
@@ -80,10 +67,24 @@
* Indicates whether this layer should be blended.
*/
bool blend;
+
/**
* Indicates whether this layer has been used already.
*/
bool empty;
+
+ /**
+ * Name of the texture used to render the layer.
+ */
+ GLuint texture;
+ /**
+ * Width of the layer texture.
+ */
+ uint32_t width;
+ /**
+ * Height of the layer texture.
+ */
+ uint32_t height;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 2183718..31da924 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -30,9 +30,7 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-LayerCache::LayerCache():
- mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
- mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
+LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
LOGD(" Setting layer cache size to %sMB", property);
@@ -42,11 +40,6 @@
}
}
-LayerCache::LayerCache(uint32_t maxByteSize):
- mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
- mSize(0), mMaxSize(maxByteSize) {
-}
-
LayerCache::~LayerCache() {
clear();
}
@@ -64,19 +57,8 @@
}
void LayerCache::setMaxSize(uint32_t maxSize) {
+ clear();
mMaxSize = maxSize;
- while (mSize > mMaxSize) {
- Layer* oldest = mCache.removeOldest();
- deleteLayer(oldest);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Callbacks
-///////////////////////////////////////////////////////////////////////////////
-
-void LayerCache::operator()(LayerSize& size, Layer*& layer) {
- deleteLayer(layer);
}
///////////////////////////////////////////////////////////////////////////////
@@ -85,7 +67,7 @@
void LayerCache::deleteLayer(Layer* layer) {
if (layer) {
- mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
+ mSize -= layer->width * layer->height * 4;
glDeleteTextures(1, &layer->texture);
delete layer;
@@ -93,21 +75,31 @@
}
void LayerCache::clear() {
- mCache.setOnEntryRemovedListener(this);
+ size_t count = mCache.size();
+ for (size_t i = 0; i < count; i++) {
+ deleteLayer(mCache.itemAt(i).mLayer);
+ }
mCache.clear();
- mCache.setOnEntryRemovedListener(NULL);
}
-Layer* LayerCache::get(LayerSize& size) {
- Layer* layer = mCache.remove(size);
- if (layer) {
- LAYER_LOGD("Reusing layer");
+Layer* LayerCache::get(const uint32_t width, const uint32_t height) {
+ Layer* layer = NULL;
- mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
+ LayerEntry entry(width, height);
+ ssize_t index = mCache.indexOf(entry);
+
+ if (index >= 0) {
+ entry = mCache.itemAt(index);
+ mCache.removeAt(index);
+
+ layer = entry.mLayer;
+ mSize -= layer->width * layer->height * 4;
+
+ LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height);
} else {
- LAYER_LOGD("Creating new layer");
+ LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
- layer = new Layer;
+ layer = new Layer(entry.mWidth, entry.mHeight);
layer->blend = true;
layer->empty = true;
layer->fbo = 0;
@@ -124,10 +116,10 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if DEBUG_LAYERS
- uint32_t size = mCache.size();
- for (uint32_t i = 0; i < size; i++) {
- LayerSize ls = mCache.getKeyAt(i);
- LAYER_LOGD(" Layer size %dx%d", ls.width, ls.height);
+ size_t size = mCache.size();
+ for (size_t i = 0; i < size; i++) {
+ const LayerEntry& entry = mCache.itemAt(i);
+ LAYER_LOGD(" Layer size %dx%d", entry.mWidth, entry.mHeight);
}
#endif
}
@@ -135,18 +127,23 @@
return layer;
}
-bool LayerCache::put(LayerSize& layerSize, Layer* layer) {
- const uint32_t size = layerSize.width * layerSize.height * 4;
+bool LayerCache::put(Layer* layer) {
+ const uint32_t size = layer->width * layer->height * 4;
// Don't even try to cache a layer that's bigger than the cache
if (size < mMaxSize) {
+ // TODO: Use an LRU
while (mSize + size > mMaxSize) {
- Layer* oldest = mCache.removeOldest();
- deleteLayer(oldest);
- LAYER_LOGD(" Deleting layer %.2fx%.2f", oldest->layer.getWidth(),
- oldest->layer.getHeight());
+ Layer* biggest = mCache.top().mLayer;
+ deleteLayer(biggest);
+ mCache.removeAt(mCache.size() - 1);
+
+ LAYER_LOGD(" Deleting layer %.2fx%.2f", biggest->layer.getWidth(),
+ biggest->layer.getHeight());
}
- mCache.put(layerSize, layer);
+ LayerEntry entry(layer);
+
+ mCache.add(entry);
mSize += size;
return true;
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index cbb7ae2..e64366f 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -18,7 +18,7 @@
#define ANDROID_UI_LAYER_CACHE_H
#include "Layer.h"
-#include "GenerationCache.h"
+#include "utils/SortedList.h"
namespace android {
namespace uirenderer {
@@ -30,6 +30,9 @@
// Debug
#define DEBUG_LAYERS 0
+// Textures used by layers must have dimensions multiples of this number
+#define LAYER_SIZE 64
+
// Debug
#if DEBUG_LAYERS
#define LAYER_LOGD(...) LOGD(__VA_ARGS__)
@@ -41,40 +44,34 @@
// Cache
///////////////////////////////////////////////////////////////////////////////
-class LayerCache: public OnEntryRemoved<LayerSize, Layer*> {
+class LayerCache {
public:
LayerCache();
- LayerCache(uint32_t maxByteSize);
~LayerCache();
/**
- * Used as a callback when an entry is removed from the cache.
- * Do not invoke directly.
- */
- void operator()(LayerSize& size, Layer*& layer);
-
- /**
- * Returns the layer of specified dimensions. If not suitable layer
- * can be found, a new one is created and returned. If creating a new
+ * Returns a layer large enough for the specified dimensions. If no suitable
+ * layer can be found, a new one is created and returned. If creating a new
* layer fails, NULL is returned.
*
* When a layer is obtained from the cache, it is removed and the total
* size of the cache goes down.
*
- * @param size The dimensions of the desired layer
+ * @param width The desired width of the layer
+ * @param width The desired height of the layer
*/
- Layer* get(LayerSize& size);
+ Layer* get(const uint32_t width, const uint32_t height);
/**
* Adds the layer to the cache. The layer will not be added if there is
- * not enough space available.
+ * not enough space available. Adding a layer can cause other layers to
+ * be removed from the cache.
*
- * @param size The dimensions of the layer
* @param layer The layer to add to the cache
*
* @return True if the layer was added, false otherwise.
*/
- bool put(LayerSize& size, Layer* layer);
+ bool put(Layer* layer);
/**
* Clears the cache. This causes all layers to be deleted.
*/
@@ -96,7 +93,41 @@
private:
void deleteLayer(Layer* layer);
- GenerationCache<LayerSize, Layer*> mCache;
+ struct LayerEntry {
+ LayerEntry():
+ mLayer(NULL), mWidth(0), mHeight(0) {
+ }
+
+ LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(NULL) {
+ mWidth = uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
+ mHeight = uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
+ }
+
+ LayerEntry(const LayerEntry& entry):
+ mLayer(entry.mLayer), mWidth(entry.mWidth), mHeight(entry.mHeight) {
+ }
+
+ LayerEntry(Layer* layer):
+ mLayer(layer), mWidth(layer->width), mHeight(layer->height) {
+ }
+
+ bool operator<(const LayerEntry& rhs) const {
+ if (mWidth == rhs.mWidth) {
+ return mHeight < rhs.mHeight;
+ }
+ return mWidth < rhs.mWidth;
+ }
+
+ bool operator==(const LayerEntry& rhs) const {
+ return mWidth == rhs.mWidth && mHeight == rhs.mHeight;
+ }
+
+ Layer* mLayer;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ }; // struct LayerEntry
+
+ SortedList<LayerEntry> mCache;
uint32_t mSize;
uint32_t mMaxSize;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5399668..5b226b4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -385,8 +385,7 @@
glActiveTexture(GL_TEXTURE0);
- LayerSize size(bounds.getWidth(), bounds.getHeight());
- Layer* layer = mCaches.layerCache.get(size);
+ Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
if (!layer) {
return false;
}
@@ -394,6 +393,8 @@
layer->mode = mode;
layer->alpha = alpha;
layer->layer.set(bounds);
+ layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height),
+ bounds.getWidth() / float(layer->width), 0.0f);
// Save the layer in the snapshot
snapshot->flags |= Snapshot::kFlagIsLayer;
@@ -420,7 +421,7 @@
// Initialize the texture if needed
if (layer->empty) {
layer->empty = false;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0,
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
@@ -455,12 +456,12 @@
// TODO: Workaround for b/3054204
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
- bounds.getWidth(), bounds.getHeight(), 0);
+ layer->width, layer->height, 0);
// TODO: Waiting for b/3054204 to be fixed
// if (layer->empty) {
// glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
- // bounds.getWidth(), bounds.getHeight(), 0);
+ // layer->width, layer->height, 0);
// layer->empty = false;
// } else {
// glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom,
@@ -502,8 +503,8 @@
layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
}
- // Layers are already drawn with a top-left origin, don't flip the texture
- resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
+ const Rect& texCoords = layer->texCoords;
+ resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
if (fboLayer) {
drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
@@ -526,9 +527,8 @@
mCaches.fboCache.put(current->fbo);
}
- LayerSize size(rect.getWidth(), rect.getHeight());
// Failing to add the layer to the cache should happen only if the layer is too large
- if (!mCaches.layerCache.put(size, layer)) {
+ if (!mCaches.layerCache.put(layer)) {
LAYER_LOGD("Deleting layer");
glDeleteTextures(1, &layer->texture);
delete layer;
@@ -692,9 +692,8 @@
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- Patch* mesh = mCaches.patchCache.get(width, height);
- mesh->updateVertices(bitmap->width(), bitmap->height(),left, top, right, bottom,
- xDivs, yDivs, width, height);
+ const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
+ right - left, bottom - top, xDivs, yDivs, width, height);
// Specify right and bottom as +1.0f from left/top to prevent scaling since the
// patch mesh already defines the final size
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 1d08c64..a9109cd 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -18,6 +18,7 @@
#define ANDROID_UI_PATCH_H
#include <sys/types.h>
+#include <cstring>
#include "Vertex.h"
@@ -28,24 +29,28 @@
* Description of a patch.
*/
struct PatchDescription {
- PatchDescription(): xCount(0), yCount(0) { }
- PatchDescription(const uint32_t xCount, const uint32_t yCount):
+ PatchDescription(): bitmapWidth(0), bitmapHeight(0),
+ pixelWidth(0), pixelHeight(0), xCount(0), yCount(0) { }
+ PatchDescription(const float bitmapWidth, const float bitmapHeight,
+ const float pixelWidth, const float pixelHeight,
+ const uint32_t xCount, const uint32_t yCount):
+ bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight),
+ pixelWidth(pixelWidth), pixelHeight(pixelHeight),
xCount(xCount), yCount(yCount) { }
PatchDescription(const PatchDescription& description):
+ bitmapWidth(description.bitmapWidth), bitmapHeight(description.bitmapHeight),
+ pixelWidth(description.pixelWidth), pixelHeight(description.pixelHeight),
xCount(description.xCount), yCount(description.yCount) { }
+ float bitmapWidth;
+ float bitmapHeight;
+ float pixelWidth;
+ float pixelHeight;
uint32_t xCount;
uint32_t yCount;
bool operator<(const PatchDescription& rhs) const {
- if (xCount == rhs.xCount) {
- return yCount < rhs.yCount;
- }
- return xCount < rhs.xCount;
- }
-
- bool operator==(const PatchDescription& rhs) const {
- return xCount == rhs.xCount && yCount == rhs.yCount;
+ return memcmp(this, &rhs, sizeof(PatchDescription)) < 0;
}
}; // struct PatchDescription
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index f2cf548..eca5e4d 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -29,10 +29,10 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-PatchCache::PatchCache(): mCache(DEFAULT_PATCH_CACHE_SIZE) {
+PatchCache::PatchCache(): mMaxEntries(DEFAULT_PATCH_CACHE_SIZE) {
}
-PatchCache::PatchCache(uint32_t maxEntries): mCache(maxEntries) {
+PatchCache::PatchCache(uint32_t maxEntries): mMaxEntries(maxEntries) {
}
PatchCache::~PatchCache() {
@@ -40,31 +40,44 @@
}
///////////////////////////////////////////////////////////////////////////////
-// Callbacks
-///////////////////////////////////////////////////////////////////////////////
-
-void PatchCache::operator()(PatchDescription& description, Patch*& mesh) {
- if (mesh) delete mesh;
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Caching
///////////////////////////////////////////////////////////////////////////////
void PatchCache::clear() {
- mCache.setOnEntryRemovedListener(this);
+ size_t count = mCache.size();
+ for (int i = 0; i < count; i++) {
+ delete mCache.valueAt(i);
+ }
mCache.clear();
- mCache.setOnEntryRemovedListener(NULL);
}
-Patch* PatchCache::get(uint32_t width, uint32_t height) {
- const PatchDescription description(width, height);
+Patch* PatchCache::get(const float bitmapWidth, const float bitmapHeight,
+ const float pixelWidth, const float pixelHeight,
+ const int32_t* xDivs, const int32_t* yDivs,
+ const uint32_t width, const uint32_t height) {
- Patch* mesh = mCache.get(description);
+ const PatchDescription description(bitmapWidth, bitmapHeight,
+ pixelWidth, pixelHeight, width, height);
+
+ ssize_t index = mCache.indexOfKey(description);
+ Patch* mesh = NULL;
+ if (index >= 0) {
+ mesh = mCache.valueAt(index);
+ }
+
if (!mesh) {
PATCH_LOGD("Creating new patch mesh, w=%d h=%d", width, height);
+
mesh = new Patch(width, height);
- mCache.put(description, mesh);
+ mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f,
+ pixelWidth, pixelHeight, xDivs, yDivs, width, height);
+
+ if (mCache.size() >= mMaxEntries) {
+ delete mCache.valueAt(mCache.size() - 1);
+ mCache.removeItemsAt(mCache.size() - 1, 1);
+ }
+
+ mCache.add(description, mesh);
}
return mesh;
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index b077469..08f78a3 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -17,8 +17,9 @@
#ifndef ANDROID_UI_PATCH_CACHE_H
#define ANDROID_UI_PATCH_CACHE_H
+#include <utils/KeyedVector.h>
+
#include "Patch.h"
-#include "GenerationCache.h"
namespace android {
namespace uirenderer {
@@ -41,23 +42,21 @@
// Cache
///////////////////////////////////////////////////////////////////////////////
-class PatchCache: public OnEntryRemoved<PatchDescription, Patch*> {
+class PatchCache {
public:
PatchCache();
PatchCache(uint32_t maxCapacity);
~PatchCache();
- /**
- * Used as a callback when an entry is removed from the cache.
- * Do not invoke directly.
- */
- void operator()(PatchDescription& description, Patch*& mesh);
-
- Patch* get(uint32_t width, uint32_t height);
+ Patch* get(const float bitmapWidth, const float bitmapHeight,
+ const float pixelWidth, const float pixelHeight,
+ const int32_t* xDivs, const int32_t* yDivs,
+ const uint32_t width, const uint32_t height);
void clear();
private:
- GenerationCache<PatchDescription, Patch*> mCache;
+ uint32_t mMaxEntries;
+ KeyedVector<PatchDescription, Patch*> mCache;
}; // class PatchCache
}; // namespace uirenderer
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index bde0e7d..596dfab 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -22,7 +22,7 @@
#include <SkPath.h>
#include "Texture.h"
-#include "GenerationCache.h"
+#include "utils/GenerationCache.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index d1a1b45..439e6fb 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -37,12 +37,8 @@
// Linear
"uniform mat4 screenSpace;\n",
// Circular
- "uniform vec2 gradientStart;\n"
- "uniform mat4 gradientMatrix;\n"
"uniform mat4 screenSpace;\n",
// Sweep
- "uniform vec2 gradientStart;\n"
- "uniform mat4 gradientMatrix;\n"
"uniform mat4 screenSpace;\n"
};
const char* gVS_Header_Uniforms_HasBitmap =
@@ -68,11 +64,9 @@
// Linear
" index = (screenSpace * position).x;\n",
// Circular
- " vec4 location = screenSpace * position;\n"
- " circular = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n",
+ " circular = (screenSpace * position).xy;\n",
// Sweep
- " vec4 location = screenSpace * position;\n"
- " sweep = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n"
+ " sweep = (screenSpace * position).xy;\n"
};
const char* gVS_Main_OutBitmapTexCoords =
" vec4 bitmapCoords = textureTransform * position;\n"
@@ -98,7 +92,6 @@
// Linear
"uniform sampler2D gradientSampler;\n",
// Circular
- "uniform float gradientRadius;\n"
"uniform sampler2D gradientSampler;\n",
// Sweep
"uniform sampler2D gradientSampler;\n"
@@ -130,7 +123,7 @@
// Linear
" vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
// Circular
- " float index = length(circular) * gradientRadius;\n"
+ " float index = length(circular);\n"
" vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
// Sweep
" float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 3012824..2c1a82b 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -44,10 +44,10 @@
// Converts a number of mega-bytes into bytes
#define MB(s) s * 1024 * 1024
-#define DEFAULT_TEXTURE_CACHE_SIZE 18.0f
-#define DEFAULT_LAYER_CACHE_SIZE 8.0f
-#define DEFAULT_PATH_CACHE_SIZE 5.0f
-#define DEFAULT_PATCH_CACHE_SIZE 100
+#define DEFAULT_TEXTURE_CACHE_SIZE 22.0f
+#define DEFAULT_LAYER_CACHE_SIZE 4.0f
+#define DEFAULT_PATH_CACHE_SIZE 4.0f
+#define DEFAULT_PATCH_CACHE_SIZE 512
#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
#define DEFAULT_FBO_CACHE_SIZE 25
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 83de2b2..fa85d20 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -49,7 +49,8 @@
SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
- mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mMatrix(matrix), mBlend(blend) {
+ mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) {
+ setMatrix(matrix);
}
SkiaShader::~SkiaShader() {
@@ -69,6 +70,11 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
}
+void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
+ screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
+ screenSpace.multiply(modelView);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Bitmap shader
///////////////////////////////////////////////////////////////////////////////
@@ -76,6 +82,7 @@
SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
+ updateLocalMatrix(matrix);
}
void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
@@ -116,14 +123,7 @@
const float height = texture->height;
mat4 textureTransform;
- if (mMatrix) {
- SkMatrix inverse;
- mMatrix->invert(&inverse);
- textureTransform.load(inverse);
- textureTransform.multiply(modelView);
- } else {
- textureTransform.load(modelView);
- }
+ computeScreenSpaceMatrix(textureTransform, modelView);
// Uniforms
bindTexture(texture->id, mWrapS, mWrapT, textureSlot);
@@ -136,15 +136,7 @@
void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
const Snapshot& snapshot) {
mat4 textureTransform;
- if (mMatrix) {
- SkMatrix inverse;
- mMatrix->invert(&inverse);
- textureTransform.load(inverse);
- textureTransform.multiply(modelView);
- } else {
- textureTransform.load(modelView);
- }
-
+ computeScreenSpaceMatrix(textureTransform, modelView);
glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
GL_FALSE, &textureTransform.data[0]);
}
@@ -192,23 +184,6 @@
description.gradientType = ProgramDescription::kGradientLinear;
}
-void SkiaLinearGradientShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
- screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
- screenSpace.multiply(modelView);
-}
-
-void SkiaLinearGradientShader::updateLocalMatrix(const SkMatrix* matrix) {
- if (matrix) {
- mat4 localMatrix(*matrix);
- mShaderMatrix.loadInverse(localMatrix);
- }
-}
-
-void SkiaLinearGradientShader::setMatrix(SkMatrix* matrix) {
- SkiaShader::setMatrix(matrix);
- updateLocalMatrix(matrix);
-}
-
void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
GLuint textureSlot = (*textureUnit)++;
@@ -239,12 +214,23 @@
// Circular gradient shader
///////////////////////////////////////////////////////////////////////////////
+static void toCircularUnitMatrix(const float x, const float y, const float radius,
+ SkMatrix* matrix) {
+ const float inv = 1.0f / radius;
+ matrix->setTranslate(-x, -y);
+ matrix->postScale(inv, inv);
+}
+
SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
SkMatrix* matrix, bool blend):
SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
- tileMode, matrix, blend),
- mRadius(radius) {
+ tileMode, matrix, blend) {
+ SkMatrix unitMatrix;
+ toCircularUnitMatrix(x, y, radius, &unitMatrix);
+ mUnitMatrix.load(unitMatrix);
+
+ updateLocalMatrix(matrix);
}
void SkiaCircularGradientShader::describe(ProgramDescription& description,
@@ -253,28 +239,31 @@
description.gradientType = ProgramDescription::kGradientCircular;
}
-void SkiaCircularGradientShader::setupProgram(Program* program, const mat4& modelView,
- const Snapshot& snapshot, GLuint* textureUnit) {
- SkiaSweepGradientShader::setupProgram(program, modelView, snapshot, textureUnit);
- glUniform1f(program->getUniform("gradientRadius"), 1.0f / mRadius);
-}
-
///////////////////////////////////////////////////////////////////////////////
// Sweep gradient shader
///////////////////////////////////////////////////////////////////////////////
+static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
+ matrix->setTranslate(-x, -y);
+}
+
SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode, matrix, blend),
- mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
+ mColors(colors), mPositions(positions), mCount(count) {
+ SkMatrix unitMatrix;
+ toSweepUnitMatrix(x, y, &unitMatrix);
+ mUnitMatrix.load(unitMatrix);
+
+ updateLocalMatrix(matrix);
}
SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
SkMatrix* matrix, bool blend):
SkiaShader(type, key, tileMode, tileMode, matrix, blend),
- mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
+ mColors(colors), mPositions(positions), mCount(count) {
}
SkiaSweepGradientShader::~SkiaSweepGradientShader() {
@@ -298,35 +287,19 @@
texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount);
}
- float left = mX;
- float top = mY;
-
- mat4 shaderMatrix;
- if (mMatrix) {
- shaderMatrix.load(*mMatrix);
- shaderMatrix.mapPoint(left, top);
- }
-
- mat4 copy(shaderMatrix);
- shaderMatrix.loadInverse(copy);
-
- snapshot.transform->mapPoint(left, top);
-
- mat4 screenSpace(*snapshot.transform);
- screenSpace.multiply(modelView);
+ mat4 screenSpace;
+ computeScreenSpaceMatrix(screenSpace, modelView);
// Uniforms
bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
glUniform1i(program->getUniform("gradientSampler"), textureSlot);
- glUniformMatrix4fv(program->getUniform("gradientMatrix"), 1, GL_FALSE, &shaderMatrix.data[0]);
- glUniform2f(program->getUniform("gradientStart"), left, top);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView,
const Snapshot& snapshot) {
- mat4 screenSpace(*snapshot.transform);
- screenSpace.multiply(modelView);
+ mat4 screenSpace;
+ computeScreenSpaceMatrix(screenSpace, modelView);
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 2c1eb35..2565e65 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -77,10 +77,21 @@
const Snapshot& snapshot) {
}
- virtual void setMatrix(SkMatrix* matrix) {
- mMatrix = matrix;
+ void setMatrix(SkMatrix* matrix) {
+ updateLocalMatrix(matrix);
}
+ void updateLocalMatrix(const SkMatrix* matrix) {
+ if (matrix) {
+ mat4 localMatrix(*matrix);
+ mShaderMatrix.loadInverse(localMatrix);
+ } else {
+ mShaderMatrix.loadIdentity();
+ }
+ }
+
+ void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
+
protected:
inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit);
@@ -88,11 +99,13 @@
SkShader* mKey;
SkShader::TileMode mTileX;
SkShader::TileMode mTileY;
- SkMatrix* mMatrix;
bool mBlend;
TextureCache* mTextureCache;
GradientCache* mGradientCache;
+
+ mat4 mUnitMatrix;
+ mat4 mShaderMatrix;
}; // struct SkiaShader
@@ -139,15 +152,7 @@
GLuint* textureUnit);
void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
- void setMatrix(SkMatrix* matrix);
-
private:
- void updateLocalMatrix(const SkMatrix* matrix);
- void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
-
- mat4 mUnitMatrix;
- mat4 mShaderMatrix;
-
float* mBounds;
uint32_t* mColors;
float* mPositions;
@@ -163,7 +168,7 @@
~SkiaSweepGradientShader();
virtual void describe(ProgramDescription& description, const Extensions& extensions);
- virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
+ void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
GLuint* textureUnit);
void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
@@ -171,7 +176,6 @@
SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions,
int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
- float mX, mY;
uint32_t* mColors;
float* mPositions;
int mCount;
@@ -185,11 +189,6 @@
int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
void describe(ProgramDescription& description, const Extensions& extensions);
- void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
- GLuint* textureUnit);
-
-private:
- float mRadius;
}; // struct SkiaCircularGradientShader
/**
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index b65d62a..16e2814 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -21,7 +21,7 @@
#include <SkPaint.h>
-#include "GenerationCache.h"
+#include "utils/GenerationCache.h"
#include "FontRenderer.h"
#include "Texture.h"
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 34c5455..467e851 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -20,7 +20,7 @@
#include <SkBitmap.h>
#include "Texture.h"
-#include "GenerationCache.h"
+#include "utils/GenerationCache.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/utils/GenerationCache.h
similarity index 97%
rename from libs/hwui/GenerationCache.h
rename to libs/hwui/utils/GenerationCache.h
index 35c6bea..5cea30f 100644
--- a/libs/hwui/GenerationCache.h
+++ b/libs/hwui/utils/GenerationCache.h
@@ -62,7 +62,7 @@
bool contains(K key) const;
V get(K key);
K getKeyAt(uint32_t index) const;
- void put(K key, V value);
+ bool put(K key, V value);
V remove(K key);
V removeOldest();
V getValueAt(uint32_t index) const;
@@ -149,7 +149,7 @@
}
template<typename K, typename V>
-void GenerationCache<K, V>::put(K key, V value) {
+bool GenerationCache<K, V>::put(K key, V value) {
if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
removeOldest();
}
@@ -158,7 +158,10 @@
if (index < 0) {
sp<Entry<K, V> > entry = new Entry<K, V>;
addToCache(entry, key, value);
+ return true;
}
+
+ return false;
}
template<typename K, typename V>
diff --git a/libs/hwui/utils/SortedList.h b/libs/hwui/utils/SortedList.h
new file mode 100644
index 0000000..68f5e9d
--- /dev/null
+++ b/libs/hwui/utils/SortedList.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_UI_SORTED_LIST_H
+#define ANDROID_UI_SORTED_LIST_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Vector.h>
+#include <utils/TypeHelpers.h>
+
+#include "SortedListImpl.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Sorted list
+///////////////////////////////////////////////////////////////////////////////
+
+template<class TYPE>
+class SortedList: private SortedListImpl {
+public:
+ typedef TYPE value_type;
+
+ SortedList();
+ SortedList(const SortedList<TYPE>& rhs);
+ virtual ~SortedList();
+
+ const SortedList<TYPE>& operator =(const SortedList<TYPE>& rhs) const;
+ SortedList<TYPE>& operator =(const SortedList<TYPE>& rhs);
+
+ inline void clear() {
+ VectorImpl::clear();
+ }
+
+ inline size_t size() const {
+ return VectorImpl::size();
+ }
+
+ inline bool isEmpty() const {
+ return VectorImpl::isEmpty();
+ }
+
+ inline size_t capacity() const {
+ return VectorImpl::capacity();
+ }
+
+ inline ssize_t setCapacity(size_t size) {
+ return VectorImpl::setCapacity(size);
+ }
+
+ inline const TYPE* array() const;
+
+ TYPE* editArray();
+
+ ssize_t indexOf(const TYPE& item) const;
+ size_t orderOf(const TYPE& item) const;
+
+ inline const TYPE& operator [](size_t index) const;
+ inline const TYPE& itemAt(size_t index) const;
+ const TYPE& top() const;
+ const TYPE& mirrorItemAt(ssize_t index) const;
+
+ ssize_t add(const TYPE& item);
+
+ TYPE& editItemAt(size_t index) {
+ return *(static_cast<TYPE *> (VectorImpl::editItemLocation(index)));
+ }
+
+ ssize_t merge(const Vector<TYPE>& vector);
+ ssize_t merge(const SortedList<TYPE>& vector);
+
+ ssize_t remove(const TYPE&);
+
+ inline ssize_t removeItemsAt(size_t index, size_t count = 1);
+ inline ssize_t removeAt(size_t index) {
+ return removeItemsAt(index);
+ }
+
+protected:
+ virtual void do_construct(void* storage, size_t num) const;
+ virtual void do_destroy(void* storage, size_t num) const;
+ virtual void do_copy(void* dest, const void* from, size_t num) const;
+ virtual void do_splat(void* dest, const void* item, size_t num) const;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const;
+ virtual int do_compare(const void* lhs, const void* rhs) const;
+}; // class SortedList
+
+///////////////////////////////////////////////////////////////////////////////
+// Implementation
+///////////////////////////////////////////////////////////////////////////////
+
+template<class TYPE>
+inline SortedList<TYPE>::SortedList():
+ SortedListImpl(sizeof(TYPE), ((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
+ | (traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
+ | (traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))) {
+}
+
+template<class TYPE>
+inline SortedList<TYPE>::SortedList(const SortedList<TYPE>& rhs): SortedListImpl(rhs) {
+}
+
+template<class TYPE> inline SortedList<TYPE>::~SortedList() {
+ finish_vector();
+}
+
+template<class TYPE>
+inline SortedList<TYPE>& SortedList<TYPE>::operator =(const SortedList<TYPE>& rhs) {
+ SortedListImpl::operator =(rhs);
+ return *this;
+}
+
+template<class TYPE>
+inline const SortedList<TYPE>& SortedList<TYPE>::operator =(
+ const SortedList<TYPE>& rhs) const {
+ SortedListImpl::operator =(rhs);
+ return *this;
+}
+
+template<class TYPE>
+inline const TYPE* SortedList<TYPE>::array() const {
+ return static_cast<const TYPE *> (arrayImpl());
+}
+
+template<class TYPE>
+inline TYPE* SortedList<TYPE>::editArray() {
+ return static_cast<TYPE *> (editArrayImpl());
+}
+
+template<class TYPE>
+inline const TYPE& SortedList<TYPE>::operator[](size_t index) const {
+ assert( index<size() );
+ return *(array() + index);
+}
+
+template<class TYPE>
+inline const TYPE& SortedList<TYPE>::itemAt(size_t index) const {
+ return operator[](index);
+}
+
+template<class TYPE>
+inline const TYPE& SortedList<TYPE>::mirrorItemAt(ssize_t index) const {
+ assert( (index>0 ? index : -index)<size() );
+ return *(array() + ((index < 0) ? (size() - index) : index));
+}
+
+template<class TYPE>
+inline const TYPE& SortedList<TYPE>::top() const {
+ return *(array() + size() - 1);
+}
+
+template<class TYPE>
+inline ssize_t SortedList<TYPE>::add(const TYPE& item) {
+ return SortedListImpl::add(&item);
+}
+
+template<class TYPE>
+inline ssize_t SortedList<TYPE>::indexOf(const TYPE& item) const {
+ return SortedListImpl::indexOf(&item);
+}
+
+template<class TYPE>
+inline size_t SortedList<TYPE>::orderOf(const TYPE& item) const {
+ return SortedListImpl::orderOf(&item);
+}
+
+template<class TYPE>
+inline ssize_t SortedList<TYPE>::merge(const Vector<TYPE>& vector) {
+ return SortedListImpl::merge(reinterpret_cast<const VectorImpl&> (vector));
+}
+
+template<class TYPE>
+inline ssize_t SortedList<TYPE>::merge(const SortedList<TYPE>& vector) {
+ return SortedListImpl::merge(reinterpret_cast<const SortedListImpl&> (vector));
+}
+
+template<class TYPE>
+inline ssize_t SortedList<TYPE>::remove(const TYPE& item) {
+ return SortedListImpl::remove(&item);
+}
+
+template<class TYPE>
+inline ssize_t SortedList<TYPE>::removeItemsAt(size_t index, size_t count) {
+ return VectorImpl::removeItemsAt(index, count);
+}
+
+template<class TYPE>
+void SortedList<TYPE>::do_construct(void* storage, size_t num) const {
+ construct_type(reinterpret_cast<TYPE*> (storage), num);
+}
+
+template<class TYPE>
+void SortedList<TYPE>::do_destroy(void* storage, size_t num) const {
+ destroy_type(reinterpret_cast<TYPE*> (storage), num);
+}
+
+template<class TYPE>
+void SortedList<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+ copy_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (from), num);
+}
+
+template<class TYPE>
+void SortedList<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+ splat_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (item), num);
+}
+
+template<class TYPE>
+void SortedList<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+ move_forward_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (from), num);
+}
+
+template<class TYPE>
+void SortedList<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+ move_backward_type(reinterpret_cast<TYPE*> (dest), reinterpret_cast<const TYPE*> (from), num);
+}
+
+template<class TYPE>
+int SortedList<TYPE>::do_compare(const void* lhs, const void* rhs) const {
+ return compare_type(*reinterpret_cast<const TYPE*> (lhs), *reinterpret_cast<const TYPE*> (rhs));
+}
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_SORTED_LIST_H
diff --git a/libs/hwui/utils/SortedListImpl.cpp b/libs/hwui/utils/SortedListImpl.cpp
new file mode 100644
index 0000000..35171d5
--- /dev/null
+++ b/libs/hwui/utils/SortedListImpl.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SortedListImpl.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Sorted list implementation, not for direct use
+///////////////////////////////////////////////////////////////////////////////
+
+SortedListImpl::SortedListImpl(size_t itemSize, uint32_t flags): VectorImpl(itemSize, flags) {
+}
+
+SortedListImpl::SortedListImpl(const VectorImpl& rhs): VectorImpl(rhs) {
+}
+
+SortedListImpl::~SortedListImpl() {
+}
+
+SortedListImpl& SortedListImpl::operator =(const SortedListImpl& rhs) {
+ return static_cast<SortedListImpl&>
+ (VectorImpl::operator =(static_cast<const VectorImpl&> (rhs)));
+}
+
+ssize_t SortedListImpl::indexOf(const void* item) const {
+ return _indexOrderOf(item);
+}
+
+size_t SortedListImpl::orderOf(const void* item) const {
+ size_t o;
+ _indexOrderOf(item, &o);
+ return o;
+}
+
+ssize_t SortedListImpl::_indexOrderOf(const void* item, size_t* order) const {
+ // binary search
+ ssize_t err = NAME_NOT_FOUND;
+ ssize_t l = 0;
+ ssize_t h = size() - 1;
+ ssize_t mid;
+ const void* a = arrayImpl();
+ const size_t s = itemSize();
+ while (l <= h) {
+ mid = l + (h - l) / 2;
+ const void* const curr = reinterpret_cast<const char *> (a) + (mid * s);
+ const int c = do_compare(curr, item);
+ if (c == 0) {
+ err = l = mid;
+ break;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ if (order) {
+ *order = l;
+ }
+ return err;
+}
+
+ssize_t SortedListImpl::add(const void* item) {
+ size_t order;
+ ssize_t index = _indexOrderOf(item, &order);
+ index = VectorImpl::insertAt(item, order, 1);
+ return index;
+}
+
+ssize_t SortedListImpl::merge(const VectorImpl& vector) {
+ // naive merge...
+ if (!vector.isEmpty()) {
+ const void* buffer = vector.arrayImpl();
+ const size_t is = itemSize();
+ size_t s = vector.size();
+ for (size_t i = 0; i < s; i++) {
+ ssize_t err = add(reinterpret_cast<const char*> (buffer) + i * is);
+ if (err < 0) {
+ return err;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+ssize_t SortedListImpl::merge(const SortedListImpl& vector) {
+ // we've merging a sorted vector... nice!
+ ssize_t err = NO_ERROR;
+ if (!vector.isEmpty()) {
+ // first take care of the case where the vectors are sorted together
+ if (do_compare(vector.itemLocation(vector.size() - 1), arrayImpl()) <= 0) {
+ err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&> (vector), 0);
+ } else if (do_compare(vector.arrayImpl(), itemLocation(size() - 1)) >= 0) {
+ err = VectorImpl::appendVector(static_cast<const VectorImpl&> (vector));
+ } else {
+ // this could be made a little better
+ err = merge(static_cast<const VectorImpl&> (vector));
+ }
+ }
+ return err;
+}
+
+ssize_t SortedListImpl::remove(const void* item) {
+ ssize_t i = indexOf(item);
+ if (i >= 0) {
+ VectorImpl::removeItemsAt(i, 1);
+ }
+ return i;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/SortedListImpl.h b/libs/hwui/utils/SortedListImpl.h
new file mode 100644
index 0000000..7da09ef
--- /dev/null
+++ b/libs/hwui/utils/SortedListImpl.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_UI_SORTED_LIST_IMPL_H
+#define ANDROID_UI_SORTED_LIST_IMPL_H
+
+#include <utils/VectorImpl.h>
+
+namespace android {
+namespace uirenderer {
+
+class SortedListImpl: public VectorImpl {
+public:
+ SortedListImpl(size_t itemSize, uint32_t flags);
+ SortedListImpl(const VectorImpl& rhs);
+ virtual ~SortedListImpl();
+
+ SortedListImpl& operator =(const SortedListImpl& rhs);
+
+ ssize_t indexOf(const void* item) const;
+ size_t orderOf(const void* item) const;
+ ssize_t add(const void* item);
+ ssize_t merge(const VectorImpl& vector);
+ ssize_t merge(const SortedListImpl& vector);
+ ssize_t remove(const void* item);
+
+protected:
+ virtual int do_compare(const void* lhs, const void* rhs) const = 0;
+
+private:
+ ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
+
+ // these are made private, because they can't be used on a SortedVector
+ // (they don't have an implementation either)
+ ssize_t add();
+ void pop();
+ void push();
+ void push(const void* item);
+ ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
+ ssize_t appendVector(const VectorImpl& vector);
+ ssize_t insertArrayAt(const void* array, size_t index, size_t length);
+ ssize_t appendArray(const void* array, size_t length);
+ ssize_t insertAt(size_t where, size_t numItems = 1);
+ ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
+ ssize_t replaceAt(size_t index);
+ ssize_t replaceAt(const void* item, size_t index);
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_SORTED_LIST_IMPL_H
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs b/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs
index 812cb7a..5445744 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs
+++ b/libs/rs/java/Fountain/src/com/android/fountain/fountain.rs
@@ -17,7 +17,6 @@
} Point_t;
Point_t *point;
-#pragma rs export_var(point, partMesh)
#pragma rs export_func(addParticles)
int root() {
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
index f5fecba..4f46810 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -11,7 +11,6 @@
float4 * ScratchPixel1;
float4 * ScratchPixel2;
-#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel1, ScratchPixel2, vBlurScript, hBlurScript)
#pragma rs export_func(filter);
rs_script vBlurScript;
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
index ce6bb1e..66315aa 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
@@ -42,11 +42,6 @@
SgTransform *gRootNode;
-#pragma rs export_var(gPVBackground, gPFBackground, gTGrid, gTestMesh, gPFSBackground, gRotate, gItalic, gTextAlloc, gTransformRS, gGroup, gRobot1, gRobot1Index, gRobot2, gRobot2Index, gRootNode)
-
-float gDT;
-int64_t gLastTime;
-
void init() {
gRotate = 0.0f;
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index 43be266..419de62 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -31,11 +31,6 @@
rs_font gItalic;
rs_allocation gTextAlloc;
-#pragma rs export_var(gPVBackground, gPFBackground, gTGrid, gTestMesh, gPFSBackground, gRotate, gItalic, gTextAlloc)
-
-float gDT;
-int64_t gLastTime;
-
void init() {
gRotate = 0.0f;
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs
index 2ef29cf..a7f5ee8 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/transform.rs
@@ -20,8 +20,6 @@
rs_script transformScript;
-#pragma rs export_var(transformScript)
-
typedef struct {
int changed;
rs_matrix4x4 *mat;
diff --git a/libs/rs/java/Samples/src/com/android/samples/rslist.rs b/libs/rs/java/Samples/src/com/android/samples/rslist.rs
index 3c3f463..f760ad0 100644
--- a/libs/rs/java/Samples/src/com/android/samples/rslist.rs
+++ b/libs/rs/java/Samples/src/com/android/samples/rslist.rs
@@ -28,8 +28,6 @@
ListAllocs *gList;
-#pragma rs export_var(gDY, gItalic, gList)
-
void init() {
gDY = 0.0f;
}
diff --git a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs
index 77384ef..8be35f8 100644
--- a/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs
+++ b/libs/rs/java/Samples/src/com/android/samples/rsrenderstates.rs
@@ -67,18 +67,6 @@
rs_program_fragment gProgFragmentCustom;
rs_program_fragment gProgFragmentMultitex;
-#pragma rs export_var(gProgVertex, gProgFragmentColor, gProgFragmentTexture)
-#pragma rs export_var(gProgStoreBlendNoneDepth, gProgStoreBlendNone, gProgStoreBlendAlpha, gProgStoreBlendAdd)
-#pragma rs export_var(gTexOpaque, gTexTorus, gTexTransparent, gTexChecker)
-#pragma rs export_var(gMbyNMesh, gTorusMesh)
-#pragma rs export_var(gFontSans, gFontSerif, gFontSerifBold, gFontSerifItalic, gFontSerifBoldItalic, gFontMono, gTextAlloc)
-#pragma rs export_var(gLinearClamp, gLinearWrap, gMipLinearWrap, gMipLinearAniso8, gMipLinearAniso15, gNearestClamp)
-#pragma rs export_var(gCullBack, gCullFront, gCullNone)
-#pragma rs export_var(gVSConstants, gFSConstants, gVSInputs, gProgVertexCustom, gProgFragmentCustom, gProgFragmentMultitex)
-
-//What we are showing
-#pragma rs export_var(gDisplayMode)
-
float gDt = 0;
void init() {
diff --git a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
index dfd77e6..066fab8 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/fp_mad.rs
@@ -2,7 +2,6 @@
const int TEST_COUNT = 1;
-#pragma rs export_var(g_results)
#pragma rs export_func(fp_mad_test)
static float data_f1[1025];
diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs
index 012af9c..ac0dc12 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs
@@ -2,21 +2,19 @@
#pragma rs export_func(primitives_test)
-#pragma rs export_var(floatTest, doubleTest, charTest, shortTest, intTest, longTest, longlongTest)
-
// Testing primitive types
-static float floatTest = 1.99f;
-static double doubleTest = 2.05;
-static char charTest = -8;
-static short shortTest = -16;
-static int intTest = -32;
-static long longTest = 17179869184l; // 1 << 34
-static long long longlongTest = 68719476736l; // 1 << 36
+float floatTest = 1.99f;
+double doubleTest = 2.05;
+char charTest = -8;
+short shortTest = -16;
+int intTest = -32;
+long longTest = 17179869184l; // 1 << 34
+long long longlongTest = 68719476736l; // 1 << 36
-static uchar ucharTest = 8;
-static ushort ushortTest = 16;
-static uint uintTest = 32;
-static int64_t int64_tTest = -17179869184l; // - 1 << 34
+uchar ucharTest = 8;
+ushort ushortTest = 16;
+uint uintTest = 32;
+int64_t int64_tTest = -17179869184l; // - 1 << 34
static bool test_primitive_types(uint32_t index) {
bool failed = false;
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs
index a5f0f6b..b2d06fe 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/rslist.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/rslist.rs
@@ -29,8 +29,6 @@
ListAllocs *gList;
-#pragma rs export_var(gDY, gFont, gList)
-
void init() {
gDY = 0.0f;
}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh
index 820fffd..21be9af 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh
+++ b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh
@@ -8,7 +8,7 @@
float score;
int64_t time;
} TestResult;
-TestResult *g_results;
+//TestResult *g_results;
static int64_t g_time;
diff --git a/libs/rs/java/tests/src/com/android/rs/test/test_root.rs b/libs/rs/java/tests/src/com/android/rs/test/test_root.rs
index 72b391dd..6dc83ba 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/test_root.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/test_root.rs
@@ -15,9 +15,6 @@
} TestResult_t;
TestResult_t *results;
-#pragma rs export_var(results)
-//#pragma rs export_func(addParticles)
-
int root() {
return 0;
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index 43bb09e..0e76dae 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -24,10 +24,37 @@
mAllocFile = __FILE__;
mAllocLine = __LINE__;
memset(&mEnviroment, 0, sizeof(mEnviroment));
+
+ mSlots = NULL;
+ mTypes = NULL;
}
Script::~Script()
{
+ if(mSlots) {
+ delete [] mSlots;
+ mSlots = NULL;
+ }
+ if(mTypes) {
+ delete [] mTypes;
+ mTypes = NULL;
+ }
+}
+
+void Script::initSlots() {
+ if(mEnviroment.mFieldCount > 0) {
+ mSlots = new ObjectBaseRef<Allocation>[mEnviroment.mFieldCount];
+ mTypes = new ObjectBaseRef<const Type>[mEnviroment.mFieldCount];
+ }
+}
+
+void Script::setSlot(uint32_t slot, Allocation *a) {
+ if(slot >= mEnviroment.mFieldCount) {
+ LOGE("Script::setSlot unable to set allocation, invalid slot index");
+ return;
+ }
+
+ mSlots[slot].set(a);
}
void Script::setVar(uint32_t slot, const void *val, uint32_t len)
@@ -51,7 +78,7 @@
{
Script *s = static_cast<Script *>(vs);
Allocation *a = static_cast<Allocation *>(va);
- s->mSlots[slot].set(a);
+ s->setSlot(slot, a);
//LOGE("rsi_ScriptBindAllocation %i %p %p", slot, a, a->getPtr());
}
@@ -61,15 +88,6 @@
s->mEnviroment.mTimeZone = timeZone;
}
-void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, bool writable, const char *name)
-{
- ScriptCState *ss = &rsc->mScriptC;
- const Type *t = static_cast<const Type *>(vt);
- ss->mConstantBufferTypes[slot].set(t);
- ss->mSlotWritable[slot] = writable;
- LOGE("rsi_ScriptSetType");
-}
-
void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
{
Script *s = static_cast<Script *>(vs);
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index 0a20344..c73bb5e 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -29,8 +29,6 @@
class ProgramRaster;
class ProgramStore;
-#define MAX_SCRIPT_BANKS 32
-
class Script : public ObjectBase
{
public:
@@ -61,10 +59,8 @@
};
Enviroment_t mEnviroment;
- ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS];
- ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS];
- bool mSlotWritable[MAX_SCRIPT_BANKS];
-
+ void initSlots();
+ void setSlot(uint32_t slot, Allocation *a);
void setVar(uint32_t slot, const void *val, uint32_t len);
virtual void runForEach(Context *rsc,
@@ -76,6 +72,10 @@
virtual void Invoke(Context *rsc, uint32_t slot, const void *data, uint32_t len) = 0;
virtual void setupScript(Context *rsc) = 0;
virtual uint32_t run(Context *) = 0;
+protected:
+ ObjectBaseRef<Allocation> *mSlots;
+ ObjectBaseRef<const Type> *mTypes;
+
};
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index c6418be..d961fed 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -365,11 +365,6 @@
void ScriptCState::clear(Context *rsc)
{
rsAssert(rsc);
- for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
- mConstantBufferTypes[ct].clear();
- mSlotWritable[ct] = false;
- }
-
mScript.clear();
mScript.set(new ScriptC(rsc));
}
@@ -428,6 +423,7 @@
else {
s->mEnviroment.mFieldAddress = (void **) calloc(s->mEnviroment.mFieldCount, sizeof(void *));
bccGetExportVars(s->mBccScript, NULL, s->mEnviroment.mFieldCount, (BCCvoid **) s->mEnviroment.mFieldAddress);
+ s->initSlots();
}
s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
@@ -532,10 +528,6 @@
ss->runCompiler(rsc, s.get());
s->incUserRef();
s->setContext(rsc);
- for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
- s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
- s->mSlotWritable[ct] = ss->mSlotWritable[ct];
- }
ss->clear(rsc);
return s.get();
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 7ec80aa..e5b5ba9 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -81,11 +81,6 @@
ObjectBaseRef<ScriptC> mScript;
- ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
- //String8 mSlotNames[MAX_SCRIPT_BANKS];
- bool mSlotWritable[MAX_SCRIPT_BANKS];
- //String8 mInvokableNames[MAX_SCRIPT_BANKS];
-
void init(Context *rsc);
void clear(Context *rsc);
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 8cdb48a..33776c3 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -31,6 +31,8 @@
mAllocLine = __LINE__;
mLODs = 0;
mLODCount = 0;
+ mAttribs = NULL;
+ mAttribsSize = 0;
clear();
}
@@ -44,6 +46,11 @@
}
if (mLODs) {
delete [] mLODs;
+ mLODs = NULL;
+ }
+ if(mAttribs) {
+ delete [] mAttribs;
+ mAttribs = NULL;
}
}
@@ -145,6 +152,21 @@
void Type::makeGLComponents()
{
+ // Count the number of gl attrs to initialize
+ mAttribsSize = 0;
+ for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
+ if(getElement()->getFieldName(ct)[0] != '#') {
+ mAttribsSize ++;
+ }
+ }
+ if(mAttribs) {
+ delete [] mAttribs;
+ mAttribs = NULL;
+ }
+ if(mAttribsSize) {
+ mAttribs = new VertexArray::Attrib[mAttribsSize];
+ }
+
uint32_t userNum = 0;
for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
const Component &c = getElement()->getField(ct)->getComponent();
@@ -160,11 +182,8 @@
String8 tmp(RS_SHADER_ATTR);
tmp.append(getElement()->getFieldName(ct));
mAttribs[userNum].name.setTo(tmp.string());
- userNum ++;
- if(userNum == RS_MAX_ATTRIBS) {
- return;
- }
+ userNum ++;
}
}
@@ -172,7 +191,13 @@
void Type::enableGLVertexBuffer(VertexArray *va) const
{
uint32_t stride = mElement->getSizeBytes();
- for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) {
+ for (uint32_t ct=0; ct < mAttribsSize; ct++) {
+ // Load up to RS_MAX_ATTRIBS inputs
+ // TODO: grow vertexarray dynamically
+ if(ct >= RS_MAX_ATTRIBS) {
+ LOGE("More GL attributes than we can handle");
+ break;
+ }
if (mAttribs[ct].size) {
va->add(mAttribs[ct], stride);
}
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index b5548c0..9099bf1 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -119,7 +119,8 @@
LOD *mLODs;
uint32_t mLODCount;
- VertexArray::Attrib mAttribs[RS_MAX_ATTRIBS];
+ VertexArray::Attrib *mAttribs;
+ uint32_t mAttribsSize;
void makeGLComponents();
private:
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
index 99fc166..9950184 100644
--- a/libs/rs/scriptc/rs_core.rsh
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -1,6 +1,30 @@
#ifndef __RS_CORE_RSH__
#define __RS_CORE_RSH__
+// Debugging, print to the LOG a description string and a value.
+extern void __attribute__((overloadable))
+ rsDebug(const char *, float);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, float, float);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, float, float, float);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, float, float, float, float);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, const rs_matrix4x4 *);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, const rs_matrix3x3 *);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, const rs_matrix2x2 *);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, int);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, uint);
+extern void __attribute__((overloadable))
+ rsDebug(const char *, const void *);
+#define RS_DEBUG(a) rsDebug(#a, a)
+#define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
+
static void __attribute__((overloadable)) rsDebug(const char *s, float2 v) {
rsDebug(s, v.x, v.y);
}
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index 5720b05..d059997 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -1,34 +1,6 @@
#ifndef __RS_MATH_RSH__
#define __RS_MATH_RSH__
-// Debugging, print to the LOG a description string and a value.
-extern void __attribute__((overloadable))
- rsDebug(const char *, float);
-extern void __attribute__((overloadable))
- rsDebug(const char *, float, float);
-extern void __attribute__((overloadable))
- rsDebug(const char *, float, float, float);
-extern void __attribute__((overloadable))
- rsDebug(const char *, float, float, float, float);
-extern void __attribute__((overloadable))
- rsDebug(const char *, const rs_matrix4x4 *);
-extern void __attribute__((overloadable))
- rsDebug(const char *, const rs_matrix3x3 *);
-extern void __attribute__((overloadable))
- rsDebug(const char *, const rs_matrix2x2 *);
-extern void __attribute__((overloadable))
- rsDebug(const char *, int);
-extern void __attribute__((overloadable))
- rsDebug(const char *, uint);
-extern void __attribute__((overloadable))
- rsDebug(const char *, const void *);
-#define RS_DEBUG(a) rsDebug(#a, a)
-#define RS_DEBUG_MARKER rsDebug(__FILE__, __LINE__)
-
-
-#include "rs_cl.rsh"
-#include "rs_core.rsh"
-
extern void __attribute__((overloadable))
rsSetObject(rs_element *dst, rs_element src);
extern void __attribute__((overloadable))
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index dd42972..212eb83 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -1,3 +1,5 @@
+#ifndef __RS_TYPES_RSH__
+#define __RS_TYPES_RSH__
typedef char int8_t;
typedef short int16_t;
@@ -72,3 +74,4 @@
#define RS_PACKED __attribute__((packed, aligned(4)))
+#endif
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 8e173aa..7adc764 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -2447,7 +2447,7 @@
yPrecision = mLocked.orientedYPrecision;
} // release lock
- getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), getSources(), policyFlags,
motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
pointerCount, pointerIds, pointerCoords,
xPrecision, yPrecision, mDownTime);
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index d2dd6eb..a5363d6 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -19,16 +19,17 @@
#include <unistd.h>
#include <fcntl.h>
-#include <sys/epoll.h>
namespace android {
+#ifdef LOOPER_USES_EPOLL
// Hint for number of file descriptors to be associated with the epoll instance.
static const int EPOLL_SIZE_HINT = 8;
// Maximum number of file descriptors for which to retrieve poll events each iteration.
static const int EPOLL_MAX_EVENTS = 16;
+#endif
static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
static pthread_key_t gTLSKey = 0;
@@ -36,9 +37,6 @@
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks),
mResponseIndex(0) {
- mEpollFd = epoll_create(EPOLL_SIZE_HINT);
- LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
-
int wakeFds[2];
int result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
@@ -54,6 +52,11 @@
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
+#ifdef LOOPER_USES_EPOLL
+ // Allocate the epoll instance and register the wake pipe.
+ mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+ LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
+
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
@@ -61,12 +64,45 @@
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
+#else
+ // Add the wake pipe to the head of the request list with a null callback.
+ struct pollfd requestedFd;
+ requestedFd.fd = mWakeReadPipeFd;
+ requestedFd.events = POLLIN;
+ mRequestedFds.push(requestedFd);
+
+ Request request;
+ request.fd = mWakeReadPipeFd;
+ request.callback = NULL;
+ request.ident = 0;
+ request.data = NULL;
+ mRequests.push(request);
+
+ mPolling = false;
+ mWaiters = 0;
+#endif
+
+#ifdef LOOPER_STATISTICS
+ mPendingWakeTime = -1;
+ mPendingWakeCount = 0;
+ mSampledWakeCycles = 0;
+ mSampledWakeCountSum = 0;
+ mSampledWakeLatencySum = 0;
+
+ mSampledPolls = 0;
+ mSampledZeroPollCount = 0;
+ mSampledZeroPollLatencySum = 0;
+ mSampledTimeoutPollCount = 0;
+ mSampledTimeoutPollLatencySum = 0;
+#endif
}
Looper::~Looper() {
close(mWakeReadPipeFd);
close(mWakeWritePipeFd);
+#ifdef LOOPER_USES_EPOLL
close(mEpollFd);
+#endif
}
void Looper::initTLSKey() {
@@ -157,45 +193,61 @@
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif
+
+ int result = ALOOPER_POLL_WAKE;
+ mResponses.clear();
+ mResponseIndex = 0;
+
+#ifdef LOOPER_STATISTICS
+ nsecs_t pollStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+
+#ifdef LOOPER_USES_EPOLL
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+ bool acquiredLock = false;
+#else
+ // Wait for wakeAndLock() waiters to run then set mPolling to true.
+ mLock.lock();
+ while (mWaiters != 0) {
+ mResume.wait(mLock);
+ }
+ mPolling = true;
+ mLock.unlock();
+
+ size_t requestedCount = mRequestedFds.size();
+ int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
+#endif
+
if (eventCount < 0) {
if (errno == EINTR) {
- return ALOOPER_POLL_WAKE;
+ goto Done;
}
LOGW("Poll failed with an unexpected error, errno=%d", errno);
- return ALOOPER_POLL_ERROR;
+ result = ALOOPER_POLL_ERROR;
+ goto Done;
}
if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - timeout", this);
#endif
- return ALOOPER_POLL_TIMEOUT;
+ result = ALOOPER_POLL_TIMEOUT;
+ goto Done;
}
- int result = ALOOPER_POLL_WAKE;
- mResponses.clear();
- mResponseIndex = 0;
-
#if DEBUG_POLL_AND_WAKE
LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif
- bool acquiredLock = false;
+
+#ifdef LOOPER_USES_EPOLL
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - awoken", this);
-#endif
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+ awoken();
} else {
LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
}
@@ -212,11 +264,7 @@
if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
-
- Response response;
- response.events = events;
- response.request = mRequests.valueAt(requestIndex);
- mResponses.push(response);
+ pushResponse(events, mRequests.valueAt(requestIndex));
} else {
LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
@@ -226,6 +274,66 @@
if (acquiredLock) {
mLock.unlock();
}
+Done: ;
+#else
+ for (size_t i = 0; i < requestedCount; i++) {
+ const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
+
+ short pollEvents = requestedFd.revents;
+ if (pollEvents) {
+ if (requestedFd.fd == mWakeReadPipeFd) {
+ if (pollEvents & POLLIN) {
+ awoken();
+ } else {
+ LOGW("Ignoring unexpected poll events 0x%x on wake read pipe.", pollEvents);
+ }
+ } else {
+ int events = 0;
+ if (pollEvents & POLLIN) events |= ALOOPER_EVENT_INPUT;
+ if (pollEvents & POLLOUT) events |= ALOOPER_EVENT_OUTPUT;
+ if (pollEvents & POLLERR) events |= ALOOPER_EVENT_ERROR;
+ if (pollEvents & POLLHUP) events |= ALOOPER_EVENT_HANGUP;
+ if (pollEvents & POLLNVAL) events |= ALOOPER_EVENT_INVALID;
+ pushResponse(events, mRequests.itemAt(i));
+ }
+ if (--eventCount == 0) {
+ break;
+ }
+ }
+ }
+
+Done:
+ // Set mPolling to false and wake up the wakeAndLock() waiters.
+ mLock.lock();
+ mPolling = false;
+ if (mWaiters != 0) {
+ mAwake.broadcast();
+ }
+ mLock.unlock();
+#endif
+
+#ifdef LOOPER_STATISTICS
+ nsecs_t pollEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ mSampledPolls += 1;
+ if (timeoutMillis == 0) {
+ mSampledZeroPollCount += 1;
+ mSampledZeroPollLatencySum += pollEndTime - pollStartTime;
+ } else if (timeoutMillis > 0 && result == ALOOPER_POLL_TIMEOUT) {
+ mSampledTimeoutPollCount += 1;
+ mSampledTimeoutPollLatencySum += pollEndTime - pollStartTime
+ - milliseconds_to_nanoseconds(timeoutMillis);
+ }
+ if (mSampledPolls == SAMPLED_POLLS_TO_AGGREGATE) {
+ LOGD("%p ~ poll latency statistics: %0.3fms zero timeout, %0.3fms non-zero timeout", this,
+ 0.000001f * float(mSampledZeroPollLatencySum) / mSampledZeroPollCount,
+ 0.000001f * float(mSampledTimeoutPollLatencySum) / mSampledTimeoutPollCount);
+ mSampledPolls = 0;
+ mSampledZeroPollCount = 0;
+ mSampledZeroPollLatencySum = 0;
+ mSampledTimeoutPollCount = 0;
+ mSampledTimeoutPollLatencySum = 0;
+ }
+#endif
for (size_t i = 0; i < mResponses.size(); i++) {
const Response& response = mResponses.itemAt(i);
@@ -278,6 +386,13 @@
LOGD("%p ~ wake", this);
#endif
+#ifdef LOOPER_STATISTICS
+ // FIXME: Possible race with awoken() but this code is for testing only and is rarely enabled.
+ if (mPendingWakeCount++ == 0) {
+ mPendingWakeTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ }
+#endif
+
ssize_t nWrite;
do {
nWrite = write(mWakeWritePipeFd, "W", 1);
@@ -290,23 +405,51 @@
}
}
+void Looper::awoken() {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ awoken", this);
+#endif
+
+#ifdef LOOPER_STATISTICS
+ if (mPendingWakeCount == 0) {
+ LOGD("%p ~ awoken: spurious!", this);
+ } else {
+ mSampledWakeCycles += 1;
+ mSampledWakeCountSum += mPendingWakeCount;
+ mSampledWakeLatencySum += systemTime(SYSTEM_TIME_MONOTONIC) - mPendingWakeTime;
+ mPendingWakeCount = 0;
+ mPendingWakeTime = -1;
+ if (mSampledWakeCycles == SAMPLED_WAKE_CYCLES_TO_AGGREGATE) {
+ LOGD("%p ~ wake statistics: %0.3fms wake latency, %0.3f wakes per cycle", this,
+ 0.000001f * float(mSampledWakeLatencySum) / mSampledWakeCycles,
+ float(mSampledWakeCountSum) / mSampledWakeCycles);
+ mSampledWakeCycles = 0;
+ mSampledWakeCountSum = 0;
+ mSampledWakeLatencySum = 0;
+ }
+ }
+#endif
+
+ char buffer[16];
+ ssize_t nRead;
+ do {
+ nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+ } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+}
+
+void Looper::pushResponse(int events, const Request& request) {
+ Response response;
+ response.events = events;
+ response.request = request;
+ mResponses.push(response);
+}
+
int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
#if DEBUG_CALLBACKS
LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
events, callback, data);
#endif
- int epollEvents = 0;
- if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
- if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
- if (events & ALOOPER_EVENT_ERROR) epollEvents |= EPOLLERR;
- if (events & ALOOPER_EVENT_HANGUP) epollEvents |= EPOLLHUP;
-
- if (epollEvents == 0) {
- LOGE("Invalid attempt to set a callback with no selected poll events.");
- return -1;
- }
-
if (! callback) {
if (! mAllowNonCallbacks) {
LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
@@ -319,6 +462,11 @@
}
}
+#ifdef LOOPER_USES_EPOLL
+ int epollEvents = 0;
+ if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
+ if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+
{ // acquire lock
AutoMutex _l(mLock);
@@ -350,6 +498,33 @@
mRequests.replaceValueAt(requestIndex, request);
}
} // release lock
+#else
+ int pollEvents = 0;
+ if (events & ALOOPER_EVENT_INPUT) pollEvents |= POLLIN;
+ if (events & ALOOPER_EVENT_OUTPUT) pollEvents |= POLLOUT;
+
+ wakeAndLock(); // acquire lock
+
+ struct pollfd requestedFd;
+ requestedFd.fd = fd;
+ requestedFd.events = pollEvents;
+
+ Request request;
+ request.fd = fd;
+ request.ident = ident;
+ request.callback = callback;
+ request.data = data;
+ ssize_t index = getRequestIndexLocked(fd);
+ if (index < 0) {
+ mRequestedFds.push(requestedFd);
+ mRequests.push(request);
+ } else {
+ mRequestedFds.replaceAt(requestedFd, size_t(index));
+ mRequests.replaceAt(request, size_t(index));
+ }
+
+ mLock.unlock(); // release lock
+#endif
return 1;
}
@@ -358,6 +533,7 @@
LOGD("%p ~ removeFd - fd=%d", this, fd);
#endif
+#ifdef LOOPER_USES_EPOLL
{ // acquire lock
AutoMutex _l(mLock);
ssize_t requestIndex = mRequests.indexOfKey(fd);
@@ -372,8 +548,49 @@
}
mRequests.removeItemsAt(requestIndex);
- } // request lock
+ } // release lock
return 1;
+#else
+ wakeAndLock(); // acquire lock
+
+ ssize_t index = getRequestIndexLocked(fd);
+ if (index >= 0) {
+ mRequestedFds.removeAt(size_t(index));
+ mRequests.removeAt(size_t(index));
+ }
+
+ mLock.unlock(); // release lock
+ return index >= 0;
+#endif
}
+#ifndef LOOPER_USES_EPOLL
+ssize_t Looper::getRequestIndexLocked(int fd) {
+ size_t requestCount = mRequestedFds.size();
+
+ for (size_t i = 0; i < requestCount; i++) {
+ if (mRequestedFds.itemAt(i).fd == fd) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void Looper::wakeAndLock() {
+ mLock.lock();
+
+ mWaiters += 1;
+ while (mPolling) {
+ wake();
+ mAwake.wait(mLock);
+ }
+
+ mWaiters -= 1;
+ if (mWaiters == 0) {
+ mResume.signal();
+ }
+}
+#endif
+
} // namespace android
diff --git a/libs/utils/tests/Looper_test.cpp b/libs/utils/tests/Looper_test.cpp
index afc92f8..cea1313 100644
--- a/libs/utils/tests/Looper_test.cpp
+++ b/libs/utils/tests/Looper_test.cpp
@@ -354,14 +354,6 @@
<< "addFd should return 1 because FD was added";
}
-TEST_F(LooperTest, AddFd_WhenEventsIsZero_ReturnsError) {
- Pipe pipe;
- int result = mLooper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
-
- EXPECT_EQ(-1, result)
- << "addFd should return -1 because arguments were invalid";
-}
-
TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
Pipe pipe;
int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index bc5f9fa..e5fa0f8 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -117,6 +117,10 @@
Files.FileColumns.DATE_MODIFIED, // 3
};
+ private static final String[] ID_PROJECTION = new String[] {
+ Files.FileColumns._ID,
+ };
+
private static final int FILES_PRESCAN_ID_COLUMN_INDEX = 0;
private static final int FILES_PRESCAN_PATH_COLUMN_INDEX = 1;
private static final int FILES_PRESCAN_FORMAT_COLUMN_INDEX = 2;
@@ -933,6 +937,14 @@
c.close();
}
}
+
+ // compute original size of images
+ mOriginalCount = 0;
+ c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null);
+ if (c != null) {
+ mOriginalCount = c.getCount();
+ c.close();
+ }
}
private boolean inScanDirectory(String path, String[] directories) {
diff --git a/media/java/android/media/MtpCursor.java b/media/java/android/media/MtpCursor.java
index ff8799a..9b5ab95 100644
--- a/media/java/android/media/MtpCursor.java
+++ b/media/java/android/media/MtpCursor.java
@@ -50,6 +50,9 @@
public MtpCursor(MtpClient client, int queryType, int deviceID, long storageID, long objectID,
String[] projection) {
+ if (client == null) {
+ throw new NullPointerException("client null in MtpCursor constructor");
+ }
mColumns = projection;
HashMap<String, Integer> map;
diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java
index 3ebad00..076cc31 100755
--- a/media/java/android/media/videoeditor/AudioTrack.java
+++ b/media/java/android/media/videoeditor/AudioTrack.java
@@ -18,17 +18,12 @@
import java.io.IOException;
-import android.util.Log;
-
/**
* This class allows to handle an audio track. This audio file is mixed with the
* audio samples of the MediaItems.
* {@hide}
*/
public class AudioTrack {
- // Logging
- private static final String TAG = "AudioTrack";
-
// Instance variables
private final String mUniqueId;
private final String mFilename;
@@ -53,129 +48,6 @@
// The audio waveform filename
private String mAudioWaveformFilename;
- private PlaybackThread mPlaybackThread;
-
- /**
- * This listener interface is used by the AudioTrack to emit playback
- * progress notifications.
- */
- public interface PlaybackProgressListener {
- /**
- * This method notifies the listener of the current time position while
- * playing an audio track
- *
- * @param audioTrack The audio track
- * @param timeMs The current playback position (expressed in milliseconds
- * since the beginning of the audio track).
- * @param end true if the end of the audio track was reached
- */
- public void onProgress(AudioTrack audioTrack, long timeMs, boolean end);
- }
-
- /**
- * The playback thread
- */
- private class PlaybackThread extends Thread {
- // Instance variables
- private final PlaybackProgressListener mListener;
- private final long mFromMs, mToMs;
- private boolean mRun;
- private final boolean mLoop;
- private long mPositionMs;
-
- /**
- * Constructor
- *
- * @param fromMs The time (relative to the beginning of the audio track)
- * at which the playback will start
- * @param toMs The time (relative to the beginning of the audio track) at
- * which the playback will stop. Use -1 to play to the end of
- * the audio track
- * @param loop true if the playback should be looped once it reaches the
- * end
- * @param listener The listener which will be notified of the playback
- * progress
- */
- public PlaybackThread(long fromMs, long toMs, boolean loop,
- PlaybackProgressListener listener) {
- mPositionMs = mFromMs = fromMs;
- if (toMs < 0) {
- mToMs = mDurationMs;
- } else {
- mToMs = toMs;
- }
- mLoop = loop;
- mListener = listener;
- mRun = true;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void run() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run enter");
- }
-
- while (mRun) {
- try {
- sleep(100);
- } catch (InterruptedException ex) {
- break;
- }
-
- mPositionMs += 100;
-
- if (mPositionMs >= mToMs) {
- if (!mLoop) {
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mPositionMs, true);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- break;
- } else {
- // Fire a notification for the end of the clip
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mToMs, false);
- }
-
- // Rewind
- mPositionMs = mFromMs;
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mPositionMs, false);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- }
- } else {
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mPositionMs, false);
- }
- }
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run exit");
- }
- }
-
- /**
- * Stop the playback
- *
- * @return The stop position
- */
- public long stopPlayback() {
- mRun = false;
- try {
- join();
- } catch (InterruptedException ex) {
- }
- return mPositionMs;
- }
- };
/**
* An object of this type cannot be instantiated by using the default
@@ -509,50 +381,6 @@
}
/**
- * Start the playback of this audio track. This method does not block (does
- * not wait for the playback to complete).
- *
- * @param fromMs The time (relative to the beginning of the audio track) at
- * which the playback will start
- * @param toMs The time (relative to the beginning of the audio track) at
- * which the playback will stop. Use -1 to play to the end of the
- * audio track
- * @param loop true if the playback should be looped once it reaches the end
- * @param listener The listener which will be notified of the playback
- * progress
- * @throws IllegalArgumentException if fromMs or toMs is beyond the playback
- * duration
- * @throws IllegalStateException if a playback, preview or an export is
- * already in progress
- */
- public void startPlayback(long fromMs, long toMs, boolean loop,
- PlaybackProgressListener listener) {
- if (fromMs >= mDurationMs) {
- return;
- }
- mPlaybackThread = new PlaybackThread(fromMs, toMs, loop, listener);
- mPlaybackThread.start();
- }
-
- /**
- * Stop the audio track playback. This method blocks until the ongoing
- * playback is stopped.
- *
- * @return The accurate current time when stop is effective expressed in
- * milliseconds
- */
- public long stopPlayback() {
- final long stopTimeMs;
- if (mPlaybackThread != null) {
- stopTimeMs = mPlaybackThread.stopPlayback();
- mPlaybackThread = null;
- } else {
- stopTimeMs = 0;
- }
- return stopTimeMs;
- }
-
- /**
* This API allows to generate a file containing the sample volume levels of
* this audio track object. This function may take significant time and is
* blocking. The filename can be retrieved using getAudioWaveformFilename().
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index dd12336..f71f4f4 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -19,7 +19,6 @@
import java.io.IOException;
import android.graphics.Bitmap;
-import android.util.Log;
import android.view.SurfaceHolder;
/**
@@ -27,9 +26,6 @@
* {@hide}
*/
public class MediaVideoItem extends MediaItem {
- // Logging
- private static final String TAG = "MediaVideoItem";
-
// Instance variables
private final int mWidth;
private final int mHeight;
@@ -50,142 +46,6 @@
private int mVolumePercentage;
private boolean mMuted;
private String mAudioWaveformFilename;
- private PlaybackThread mPlaybackThread;
-
- /**
- * This listener interface is used by the MediaVideoItem to emit playback
- * progress notifications. This callback should be invoked after the
- * number of frames specified by
- * {@link #startPlayback(SurfaceHolder surfaceHolder, long fromMs,
- * int callbackAfterFrameCount, PlaybackProgressListener listener)}
- */
- public interface PlaybackProgressListener {
- /**
- * This method notifies the listener of the current time position while
- * playing a media item
- *
- * @param mediaItem The media item
- * @param timeMs The current playback position (expressed in milliseconds
- * since the beginning of the media item).
- * @param end true if the end of the media item was reached
- */
- public void onProgress(MediaVideoItem mediaItem, long timeMs, boolean end);
- }
-
- /**
- * The playback thread
- */
- private class PlaybackThread extends Thread {
- // Instance variables
- private final static long FRAME_DURATION = 33;
- private final PlaybackProgressListener mListener;
- private final int mCallbackAfterFrameCount;
- private final long mFromMs, mToMs;
- private boolean mRun;
- private final boolean mLoop;
- private long mPositionMs;
-
- /**
- * Constructor
- *
- * @param fromMs The time (relative to the beginning of the media item)
- * at which the playback will start
- * @param toMs The time (relative to the beginning of the media item) at
- * which the playback will stop. Use -1 to play to the end of
- * the media item
- * @param loop true if the playback should be looped once it reaches the
- * end
- * @param callbackAfterFrameCount The listener interface should be
- * invoked after the number of frames specified by this
- * parameter.
- * @param listener The listener which will be notified of the playback
- * progress
- */
- public PlaybackThread(long fromMs, long toMs, boolean loop, int callbackAfterFrameCount,
- PlaybackProgressListener listener) {
- mPositionMs = mFromMs = fromMs;
- if (toMs < 0) {
- mToMs = mDurationMs;
- } else {
- mToMs = toMs;
- }
- mLoop = loop;
- mCallbackAfterFrameCount = callbackAfterFrameCount;
- mListener = listener;
- mRun = true;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void run() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run enter");
- }
- int frameCount = 0;
- while (mRun) {
- try {
- sleep(FRAME_DURATION);
- } catch (InterruptedException ex) {
- break;
- }
- frameCount++;
- mPositionMs += FRAME_DURATION;
-
- if (mPositionMs >= mToMs) {
- if (!mLoop) {
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mPositionMs, true);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- break;
- } else {
- // Fire a notification for the end of the clip
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mToMs, false);
- }
-
- // Rewind
- mPositionMs = mFromMs;
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mPositionMs, false);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- frameCount = 0;
- }
- } else {
- if (frameCount == mCallbackAfterFrameCount) {
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mPositionMs, false);
- }
- frameCount = 0;
- }
- }
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run exit");
- }
- }
-
- /**
- * Stop the playback
- *
- * @return The stop position
- */
- public long stopPlayback() {
- mRun = false;
- try {
- join();
- } catch (InterruptedException ex) {
- }
- return mPositionMs;
- }
- };
/**
* An object of this type cannot be instantiated with a default constructor
@@ -408,57 +268,6 @@
}
/**
- * Start the playback of this media item. This method does not block (does
- * not wait for the playback to complete). The PlaybackProgressListener
- * allows to track the progress at the time interval determined by the
- * callbackAfterFrameCount parameter. The SurfaceHolder has to be created
- * and ready for use before calling this method.
- *
- * @param surfaceHolder SurfaceHolder where the frames are rendered.
- * @param fromMs The time (relative to the beginning of the media item) at
- * which the playback will start
- * @param toMs The time (relative to the beginning of the media item) at
- * which the playback will stop. Use -1 to play to the end of the
- * media item
- * @param loop true if the playback should be looped once it reaches the end
- * @param callbackAfterFrameCount The listener interface should be invoked
- * after the number of frames specified by this parameter.
- * @param listener The listener which will be notified of the playback
- * progress
- * @throws IllegalArgumentException if fromMs or toMs is beyond the playback
- * duration
- * @throws IllegalStateException if a playback, preview or an export is
- * already in progress
- */
- public void startPlayback(SurfaceHolder surfaceHolder, long fromMs, long toMs, boolean loop,
- int callbackAfterFrameCount, PlaybackProgressListener listener) {
- if (fromMs >= mDurationMs) {
- return;
- }
- mPlaybackThread = new PlaybackThread(fromMs, toMs, loop, callbackAfterFrameCount,
- listener);
- mPlaybackThread.start();
- }
-
- /**
- * Stop the media item playback. This method blocks until the ongoing
- * playback is stopped.
- *
- * @return The accurate current time when stop is effective expressed in
- * milliseconds
- */
- public long stopPlayback() {
- final long stopTimeMs;
- if (mPlaybackThread != null) {
- stopTimeMs = mPlaybackThread.stopPlayback();
- mPlaybackThread = null;
- } else {
- stopTimeMs = 0;
- }
- return stopTimeMs;
- }
-
- /**
* This API allows to generate a file containing the sample volume levels of
* the Audio track of this media item. This function may take significant
* time and is blocking. The file can be retrieved using
diff --git a/media/java/android/media/videoeditor/VideoEditorFactory.java b/media/java/android/media/videoeditor/VideoEditorFactory.java
index 0a377e2..41eed16 100755
--- a/media/java/android/media/videoeditor/VideoEditorFactory.java
+++ b/media/java/android/media/videoeditor/VideoEditorFactory.java
@@ -63,6 +63,12 @@
if (!dir.exists()) {
if (!dir.mkdirs()) {
throw new FileNotFoundException("Cannot create project path: " + projectPath);
+ } else {
+ // Create the file which hides the media files
+ // from the media scanner
+ if (!new File(dir, ".nomedia").createNewFile()) {
+ throw new FileNotFoundException("Cannot create file .nomedia");
+ }
}
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 7a78185..06d5cd5 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -20,7 +20,6 @@
#include "StagefrightRecorder.h"
-#include <binder/IPCThreadState.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/CameraSource.h>
@@ -35,7 +34,6 @@
#include <media/stagefright/OMXCodec.h>
#include <media/MediaProfiles.h>
#include <camera/ICamera.h>
-#include <camera/Camera.h>
#include <camera/CameraParameters.h>
#include <surfaceflinger/Surface.h>
#include <utils/Errors.h>
@@ -184,22 +182,7 @@
return BAD_VALUE;
}
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- mFlags &= ~FLAGS_HOT_CAMERA;
- mCamera = Camera::create(camera);
- if (mCamera == 0) {
- LOGE("Unable to connect to camera");
- IPCThreadState::self()->restoreCallingIdentity(token);
- return -EBUSY;
- }
-
- LOGV("Connected to camera");
- if (mCamera->previewEnabled()) {
- LOGV("camera is hot");
- mFlags |= FLAGS_HOT_CAMERA;
- }
- IPCThreadState::self()->restoreCallingIdentity(token);
-
+ mCamera = camera;
return OK;
}
@@ -966,66 +949,7 @@
}
}
-/*
- * Check to see whether the requested video width and height is one
- * of the supported sizes. It returns true if so; otherwise, it
- * returns false.
- */
-bool StagefrightRecorder::isVideoSizeSupported(
- const Vector<Size>& supportedSizes) const {
-
- LOGV("isVideoSizeSupported");
- for (size_t i = 0; i < supportedSizes.size(); ++i) {
- if (mVideoWidth == supportedSizes[i].width &&
- mVideoHeight == supportedSizes[i].height) {
- return true;
- }
- }
- return false;
-}
-
-/*
- * If the preview and video output is separate, we only set the
- * the video size, and applications should set the preview size
- * to some proper value, and the recording framework will not
- * change the preview size; otherwise, if the video and preview
- * output is the same, we need to set the preview to be the same
- * as the requested video size.
- *
- * On return, it also returns whether the setVideoSize() is
- * supported.
- */
-status_t StagefrightRecorder::setCameraVideoSize(
- CameraParameters* params,
- bool* isSetVideoSizeSupported) {
- LOGV("setCameraVideoSize: %dx%d", mVideoWidth, mVideoHeight);
-
- // Check whether the requested video size is supported
- Vector<Size> sizes;
- params->getSupportedVideoSizes(sizes);
- *isSetVideoSizeSupported = true;
- if (sizes.size() == 0) {
- LOGD("Camera does not support setVideoSize()");
- params->getSupportedPreviewSizes(sizes);
- *isSetVideoSizeSupported = false;
- }
- if (!isVideoSizeSupported(sizes)) {
- LOGE("Camera does not support video size (%dx%d)!",
- mVideoWidth, mVideoHeight);
- return BAD_VALUE;
- }
-
- // Actually set the video size
- if (isSetVideoSizeSupported) {
- params->setVideoSize(mVideoWidth, mVideoHeight);
- } else {
- params->setPreviewSize(mVideoWidth, mVideoHeight);
- }
-
- return OK;
-}
-
-status_t StagefrightRecorder::setupCamera() {
+status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
if (!mCaptureTimeLapse) {
// Dont clip for time lapse capture as encoder will have enough
// time to encode because of slow capture rate of time lapse.
@@ -1034,67 +958,6 @@
clipVideoFrameWidth();
clipVideoFrameHeight();
}
-
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- if (mCamera == 0) {
- mCamera = Camera::connect(mCameraId);
- if (mCamera == 0) {
- LOGE("Camera connection could not be established.");
- return -EBUSY;
- }
- mFlags &= ~FLAGS_HOT_CAMERA;
- mCamera->lock();
- }
-
- // Set the actual video recording frame size
- CameraParameters params(mCamera->getParameters());
-
- // dont change the preview size because time lapse may be using still camera
- // as mVideoWidth, mVideoHeight may correspond to HD resolution not
- // supported by the video camera.
- bool isSetVideoSizeSupported = false;
- if (!mCaptureTimeLapse) {
- if (OK != setCameraVideoSize(¶ms, &isSetVideoSizeSupported)) {
- return BAD_VALUE;
- }
- }
-
- params.setPreviewFrameRate(mFrameRate);
- String8 s = params.flatten();
- if (OK != mCamera->setParameters(s)) {
- LOGE("Could not change settings."
- " Someone else is using camera %d?", mCameraId);
- return -EBUSY;
- }
- CameraParameters newCameraParams(mCamera->getParameters());
-
- // Check on video frame size
- int frameWidth = 0, frameHeight = 0;
- if (isSetVideoSizeSupported) {
- newCameraParams.getVideoSize(&frameWidth, &frameHeight);
- } else {
- newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
- }
- if (!mCaptureTimeLapse &&
- (frameWidth < 0 || frameWidth != mVideoWidth ||
- frameHeight < 0 || frameHeight != mVideoHeight)) {
- LOGE("Failed to set the video frame size to %dx%d",
- mVideoWidth, mVideoHeight);
- IPCThreadState::self()->restoreCallingIdentity(token);
- return UNKNOWN_ERROR;
- }
-
- // Check on video frame rate
- int frameRate = newCameraParams.getPreviewFrameRate();
- if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
- LOGE("Failed to set frame rate to %d fps. The actual "
- "frame rate is %d", mFrameRate, frameRate);
- }
-
- // This CHECK is good, since we just passed the lock/unlock
- // check earlier by calling mCamera->setParameters().
- CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
- IPCThreadState::self()->restoreCallingIdentity(token);
return OK;
}
@@ -1116,15 +979,18 @@
}
status_t StagefrightRecorder::setupCameraSource(sp<CameraSource> *cameraSource) {
- status_t err = setupCamera();
- if (err != OK) return err;
-
+ Size videoSize;
+ videoSize.width = mVideoWidth;
+ videoSize.height = mVideoHeight;
if (mCaptureTimeLapse) {
- mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(mCamera,
- mTimeBetweenTimeLapseFrameCaptureUs, mVideoWidth, mVideoHeight, mFrameRate);
+ mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
+ mCamera, mCameraId,
+ videoSize, mFrameRate, mPreviewSurface,
+ mTimeBetweenTimeLapseFrameCaptureUs);
*cameraSource = mCameraSourceTimeLapse;
} else {
- *cameraSource = CameraSource::CreateFromCamera(mCamera);
+ *cameraSource = CameraSource::CreateFromCamera(
+ mCamera, mCameraId, videoSize, mFrameRate, mPreviewSurface);
}
CHECK(*cameraSource != NULL);
@@ -1411,19 +1277,6 @@
mWriter.clear();
}
- if (mCamera != 0) {
- LOGV("Disconnect camera");
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- if ((mFlags & FLAGS_HOT_CAMERA) == 0) {
- LOGV("Camera was cold when we started, stopping preview");
- mCamera->stopPreview();
- }
- mCamera->unlock();
- mCamera.clear();
- IPCThreadState::self()->restoreCallingIdentity(token);
- mFlags = 0;
- }
-
if (mOutputFd >= 0) {
::close(mOutputFd);
mOutputFd = -1;
@@ -1490,7 +1343,6 @@
mOutputFd = -1;
mOutputFdAux = -1;
- mFlags = 0;
return OK;
}
@@ -1561,8 +1413,6 @@
result.append(buffer);
snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
result.append(buffer);
- snprintf(buffer, SIZE, " Camera flags: %d\n", mFlags);
- result.append(buffer);
snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
result.append(buffer);
snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index f14c704..039bc16 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -63,12 +63,7 @@
virtual status_t dump(int fd, const Vector<String16>& args) const;
private:
- enum CameraFlags {
- FLAGS_SET_CAMERA = 1L << 0,
- FLAGS_HOT_CAMERA = 1L << 1,
- };
-
- sp<Camera> mCamera;
+ sp<ICamera> mCamera;
sp<Surface> mPreviewSurface;
sp<IMediaRecorderClient> mListener;
sp<MediaWriter> mWriter, mWriterAux;
@@ -107,7 +102,6 @@
String8 mParams;
int mOutputFd, mOutputFdAux;
- int32_t mFlags;
MediaProfiles *mEncoderProfiles;
@@ -125,10 +119,7 @@
status_t startAACRecording();
status_t startRTPRecording();
sp<MediaSource> createAudioSource();
- status_t setupCamera();
- bool isVideoSizeSupported(const Vector<Size>& supportedSizes) const;
- status_t setCameraVideoSize(CameraParameters* params,
- bool *isSetVideoSizeSupported);
+ status_t checkVideoEncoderCapabilities();
status_t setupCameraSource(sp<CameraSource> *cameraSource);
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
status_t setupVideoEncoder(
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 4f5ff75..82f14a3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -564,6 +564,39 @@
postBufferingEvent_l();
}
+void AwesomePlayer::partial_reset_l() {
+ // Only reset the video renderer and shut down the video decoder.
+ // Then instantiate a new video decoder and resume video playback.
+
+ mVideoRenderer.clear();
+
+ if (mLastVideoBuffer) {
+ mLastVideoBuffer->release();
+ mLastVideoBuffer = NULL;
+ }
+
+ if (mVideoBuffer) {
+ mVideoBuffer->release();
+ mVideoBuffer = NULL;
+ }
+
+ {
+ mVideoSource->stop();
+
+ // The following hack is necessary to ensure that the OMX
+ // component is completely released by the time we may try
+ // to instantiate it again.
+ wp<MediaSource> tmp = mVideoSource;
+ mVideoSource.clear();
+ while (tmp.promote() != NULL) {
+ usleep(1000);
+ }
+ IPCThreadState::self()->flushCommands();
+ }
+
+ CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
+}
+
void AwesomePlayer::onStreamDone() {
// Posted whenever any stream finishes playing.
@@ -573,7 +606,21 @@
}
mStreamDoneEventPending = false;
- if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
+ if (mStreamDoneStatus == INFO_DISCONTINUITY) {
+ // This special status is returned because an http live stream's
+ // video stream switched to a different bandwidth at this point
+ // and future data may have been encoded using different parameters.
+ // This requires us to shutdown the video decoder and reinstantiate
+ // a fresh one.
+
+ LOGV("INFO_DISCONTINUITY");
+
+ CHECK(mVideoSource != NULL);
+
+ partial_reset_l();
+ postVideoEvent_l();
+ return;
+ } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
notifyListener_l(
@@ -959,8 +1006,7 @@
mVideoTrack = source;
}
-status_t AwesomePlayer::initVideoDecoder() {
- uint32_t flags = 0;
+status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
false, // createEncoder
@@ -1593,21 +1639,30 @@
if (mLastVideoBuffer) {
size_t size = mLastVideoBuffer->range_length();
+
if (size) {
- state->mLastVideoFrameSize = size;
- state->mLastVideoFrame = malloc(size);
- memcpy(state->mLastVideoFrame,
- (const uint8_t *)mLastVideoBuffer->data()
- + mLastVideoBuffer->range_offset(),
- size);
+ int32_t unreadable;
+ if (!mLastVideoBuffer->meta_data()->findInt32(
+ kKeyIsUnreadable, &unreadable)
+ || unreadable == 0) {
+ state->mLastVideoFrameSize = size;
+ state->mLastVideoFrame = malloc(size);
+ memcpy(state->mLastVideoFrame,
+ (const uint8_t *)mLastVideoBuffer->data()
+ + mLastVideoBuffer->range_offset(),
+ size);
- state->mVideoWidth = mVideoWidth;
- state->mVideoHeight = mVideoHeight;
+ state->mVideoWidth = mVideoWidth;
+ state->mVideoHeight = mVideoHeight;
- sp<MetaData> meta = mVideoSource->getFormat();
- CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
- CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
- CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
+ sp<MetaData> meta = mVideoSource->getFormat();
+ CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
+ CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
+ CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
+ } else {
+ LOGV("Unable to save last video frame, we have no access to "
+ "the decoded video data.");
+ }
}
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 0c9eef4..1eb394a 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -27,6 +27,7 @@
#include <media/stagefright/MetaData.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
+#include <surfaceflinger/Surface.h>
#include <utils/String8.h>
#include <cutils/properties.h>
@@ -108,28 +109,45 @@
CHECK_EQ(0, "Unknown color format");
}
-// static
CameraSource *CameraSource::Create() {
- sp<Camera> camera = Camera::connect(0);
+ Size size;
+ size.width = -1;
+ size.height = -1;
- if (camera.get() == NULL) {
- return NULL;
- }
-
- return new CameraSource(camera);
+ sp<ICamera> camera;
+ return new CameraSource(camera, 0, size, -1, NULL);
}
// static
-CameraSource *CameraSource::CreateFromCamera(const sp<Camera> &camera) {
- if (camera.get() == NULL) {
- return NULL;
- }
+CameraSource *CameraSource::CreateFromCamera(
+ const sp<ICamera>& camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t frameRate,
+ const sp<Surface>& surface) {
- return new CameraSource(camera);
+ CameraSource *source = new CameraSource(camera, cameraId,
+ videoSize, frameRate, surface);
+
+ if (source != NULL) {
+ if (source->initCheck() != OK) {
+ delete source;
+ return NULL;
+ }
+ }
+ return source;
}
-CameraSource::CameraSource(const sp<Camera> &camera)
- : mCamera(camera),
+CameraSource::CameraSource(
+ const sp<ICamera>& camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t frameRate,
+ const sp<Surface>& surface)
+ : mCameraFlags(0),
+ mVideoFrameRate(-1),
+ mCamera(0),
+ mSurface(surface),
mNumFramesReceived(0),
mLastFrameTimestampUs(0),
mStarted(false),
@@ -140,39 +158,337 @@
mGlitchDurationThresholdUs(200000),
mCollectStats(false) {
+ mVideoSize.width = -1;
+ mVideoSize.height = -1;
+
+ mInitCheck = init(camera, cameraId, videoSize, frameRate);
+}
+
+status_t CameraSource::initCheck() const {
+ return mInitCheck;
+}
+
+status_t CameraSource::isCameraAvailable(
+ const sp<ICamera>& camera, int32_t cameraId) {
+
+ if (camera == 0) {
+ mCamera = Camera::connect(cameraId);
+ mCameraFlags &= ~FLAGS_HOT_CAMERA;
+ } else {
+ mCamera = Camera::create(camera);
+ mCameraFlags |= FLAGS_HOT_CAMERA;
+ }
+
+ // Is camera available?
+ if (mCamera == 0) {
+ LOGE("Camera connection could not be established.");
+ return -EBUSY;
+ }
+ if (!(mCameraFlags & FLAGS_HOT_CAMERA)) {
+ mCamera->lock();
+ }
+ return OK;
+}
+
+
+/*
+ * Check to see whether the requested video width and height is one
+ * of the supported sizes.
+ * @param width the video frame width in pixels
+ * @param height the video frame height in pixels
+ * @param suppportedSizes the vector of sizes that we check against
+ * @return true if the dimension (width and height) is supported.
+ */
+static bool isVideoSizeSupported(
+ int32_t width, int32_t height,
+ const Vector<Size>& supportedSizes) {
+
+ LOGV("isVideoSizeSupported");
+ for (size_t i = 0; i < supportedSizes.size(); ++i) {
+ if (width == supportedSizes[i].width &&
+ height == supportedSizes[i].height) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * If the preview and video output is separate, we only set the
+ * the video size, and applications should set the preview size
+ * to some proper value, and the recording framework will not
+ * change the preview size; otherwise, if the video and preview
+ * output is the same, we need to set the preview to be the same
+ * as the requested video size.
+ *
+ */
+/*
+ * Query the camera to retrieve the supported video frame sizes
+ * and also to see whether CameraParameters::setVideoSize()
+ * is supported or not.
+ * @param params CameraParameters to retrieve the information
+ * @@param isSetVideoSizeSupported retunrs whether method
+ * CameraParameters::setVideoSize() is supported or not.
+ * @param sizes returns the vector of Size objects for the
+ * supported video frame sizes advertised by the camera.
+ */
+static void getSupportedVideoSizes(
+ const CameraParameters& params,
+ bool *isSetVideoSizeSupported,
+ Vector<Size>& sizes) {
+
+ *isSetVideoSizeSupported = true;
+ params.getSupportedVideoSizes(sizes);
+ if (sizes.size() == 0) {
+ LOGD("Camera does not support setVideoSize()");
+ params.getSupportedPreviewSizes(sizes);
+ *isSetVideoSizeSupported = false;
+ }
+}
+
+/*
+ * Check whether the camera has the supported color format
+ * @param params CameraParameters to retrieve the information
+ * @return OK if no error.
+ */
+status_t CameraSource::isCameraColorFormatSupported(
+ const CameraParameters& params) {
+ mColorFormat = getColorFormat(params.get(
+ CameraParameters::KEY_VIDEO_FRAME_FORMAT));
+ if (mColorFormat == -1) {
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+/*
+ * Configure the camera to use the requested video size
+ * (width and height) and/or frame rate. If both width and
+ * height are -1, configuration on the video size is skipped.
+ * if frameRate is -1, configuration on the frame rate
+ * is skipped. Skipping the configuration allows one to
+ * use the current camera setting without the need to
+ * actually know the specific values (see Create() method).
+ *
+ * @param params the CameraParameters to be configured
+ * @param width the target video frame width in pixels
+ * @param height the target video frame height in pixels
+ * @param frameRate the target frame rate in frames per second.
+ * @return OK if no error.
+ */
+status_t CameraSource::configureCamera(
+ CameraParameters* params,
+ int32_t width, int32_t height,
+ int32_t frameRate) {
+
+ Vector<Size> sizes;
+ bool isSetVideoSizeSupportedByCamera = true;
+ getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
+ bool isCameraParamChanged = false;
+ if (width != -1 && height != -1) {
+ if (!isVideoSizeSupported(width, height, sizes)) {
+ LOGE("Video dimension (%dx%d) is unsupported", width, height);
+ return BAD_VALUE;
+ }
+ if (isSetVideoSizeSupportedByCamera) {
+ params->setVideoSize(width, height);
+ } else {
+ params->setPreviewSize(width, height);
+ }
+ isCameraParamChanged = true;
+ } else if ((width == -1 && height != -1) ||
+ (width != -1 && height == -1)) {
+ // If one and only one of the width and height is -1
+ // we reject such a request.
+ LOGE("Requested video size (%dx%d) is not supported", width, height);
+ return BAD_VALUE;
+ } else { // width == -1 && height == -1
+ // Do not configure the camera.
+ // Use the current width and height value setting from the camera.
+ }
+
+ if (frameRate != -1) {
+ params->setPreviewFrameRate(frameRate);
+ isCameraParamChanged = true;
+ } else { // frameRate == -1
+ // Do not configure the camera.
+ // Use the current frame rate value setting from the camera
+ }
+
+ if (isCameraParamChanged) {
+ // Either frame rate or frame size needs to be changed.
+ String8 s = params->flatten();
+ if (OK != mCamera->setParameters(s)) {
+ LOGE("Could not change settings."
+ " Someone else is using camera %p?", mCamera.get());
+ return -EBUSY;
+ }
+ }
+ return OK;
+}
+
+/*
+ * Check whether the requested video frame size
+ * has been successfully configured or not. If both width and height
+ * are -1, check on the current width and height value setting
+ * is performed.
+ *
+ * @param params CameraParameters to retrieve the information
+ * @param the target video frame width in pixels to check against
+ * @param the target video frame height in pixels to check against
+ * @return OK if no error
+ */
+status_t CameraSource::checkVideoSize(
+ const CameraParameters& params,
+ int32_t width, int32_t height) {
+
+ int32_t frameWidthActual = -1;
+ int32_t frameHeightActual = -1;
+ params.getPreviewSize(&frameWidthActual, &frameHeightActual);
+ if (frameWidthActual < 0 || frameHeightActual < 0) {
+ LOGE("Failed to retrieve video frame size (%dx%d)",
+ frameWidthActual, frameHeightActual);
+ return UNKNOWN_ERROR;
+ }
+
+ // Check the actual video frame size against the target/requested
+ // video frame size.
+ if (width != -1 && height != -1) {
+ if (frameWidthActual != width || frameHeightActual != height) {
+ LOGE("Failed to set video frame size to %dx%d. "
+ "The actual video size is %dx%d ", width, height,
+ frameWidthActual, frameHeightActual);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Good now.
+ mVideoSize.width = frameWidthActual;
+ mVideoSize.height = frameHeightActual;
+ return OK;
+}
+
+/*
+ * Check the requested frame rate has been successfully configured or not.
+ * If the target frameRate is -1, check on the current frame rate value
+ * setting is performed.
+ *
+ * @param params CameraParameters to retrieve the information
+ * @param the target video frame rate to check against
+ * @return OK if no error.
+ */
+status_t CameraSource::checkFrameRate(
+ const CameraParameters& params,
+ int32_t frameRate) {
+
+ int32_t frameRateActual = params.getPreviewFrameRate();
+ if (frameRateActual < 0) {
+ LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
+ return UNKNOWN_ERROR;
+ }
+
+ // Check the actual video frame rate against the target/requested
+ // video frame rate.
+ if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
+ LOGE("Failed to set preview frame rate to %d fps. The actual "
+ "frame rate is %d", frameRate, frameRateActual);
+ return UNKNOWN_ERROR;
+ }
+
+ // Good now.
+ mVideoFrameRate = frameRateActual;
+ return OK;
+}
+
+/*
+ * Initialize the CameraSource to so that it becomes
+ * ready for providing the video input streams as requested.
+ * @param camera the camera object used for the video source
+ * @param cameraId if camera == 0, use camera with this id
+ * as the video source
+ * @param videoSize the target video frame size. If both
+ * width and height in videoSize is -1, use the current
+ * width and heigth settings by the camera
+ * @param frameRate the target frame rate in frames per second.
+ * if it is -1, use the current camera frame rate setting.
+ * @return OK if no error.
+ */
+status_t CameraSource::init(
+ const sp<ICamera>& camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t frameRate) {
+
+ status_t err = OK;
int64_t token = IPCThreadState::self()->clearCallingIdentity();
- String8 s = mCamera->getParameters();
+
+ if ((err = isCameraAvailable(camera, cameraId)) != OK) {
+ return err;
+ }
+ CameraParameters params(mCamera->getParameters());
+ if ((err = isCameraColorFormatSupported(params)) != OK) {
+ return err;
+ }
+
+ // Set the camera to use the requested video frame size
+ // and/or frame rate.
+ if ((err = configureCamera(¶ms,
+ videoSize.width, videoSize.height,
+ frameRate))) {
+ return err;
+ }
+
+ // Check on video frame size and frame rate.
+ CameraParameters newCameraParams(mCamera->getParameters());
+ if ((err = checkVideoSize(newCameraParams,
+ videoSize.width, videoSize.height)) != OK) {
+ return err;
+ }
+ if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) {
+ return err;
+ }
+
+ // This CHECK is good, since we just passed the lock/unlock
+ // check earlier by calling mCamera->setParameters().
+ CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface));
+
+ /*
+ * mCamera->startRecording() signals camera hal to make
+ * available the video buffers (for instance, allocation
+ * of the video buffers may be triggered when camera hal's
+ * startRecording() method is called). Making available these
+ * video buffers earlier (before calling start()) is critical,
+ * if one wants to configure omx video encoders to use these
+ * buffers for passing video frame data during video recording
+ * without the need to memcpy the video frame data stored
+ * in these buffers. Eliminating memcpy for video frame data
+ * is crucial in performance for HD quality video recording
+ * applications.
+ *
+ * Based on OMX IL spec, configuring the omx video encoders
+ * must occur in loaded state. When start() is called, omx
+ * video encoders are already in idle state, which is too
+ * late. Thus, we must call mCamera->startRecording() earlier.
+ */
+ startCameraRecording();
+
IPCThreadState::self()->restoreCallingIdentity(token);
- printf("params: \"%s\"\n", s.string());
-
- int32_t width, height, stride, sliceHeight;
- CameraParameters params(s);
- params.getPreviewSize(&width, &height);
-
- // Calculate glitch duraton threshold based on frame rate
- int32_t frameRate = params.getPreviewFrameRate();
- int64_t glitchDurationUs = (1000000LL / frameRate);
+ int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
if (glitchDurationUs > mGlitchDurationThresholdUs) {
mGlitchDurationThresholdUs = glitchDurationUs;
}
- const char *colorFormatStr = params.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
- CHECK(colorFormatStr != NULL);
- int32_t colorFormat = getColorFormat(colorFormatStr);
-
// XXX: query camera for the stride and slice height
// when the capability becomes available.
- stride = width;
- sliceHeight = height;
-
mMeta = new MetaData;
- mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
- mMeta->setInt32(kKeyColorFormat, colorFormat);
- mMeta->setInt32(kKeyWidth, width);
- mMeta->setInt32(kKeyHeight, height);
- mMeta->setInt32(kKeyStride, stride);
- mMeta->setInt32(kKeySliceHeight, sliceHeight);
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
+ mMeta->setInt32(kKeyColorFormat, mColorFormat);
+ mMeta->setInt32(kKeyWidth, mVideoSize.width);
+ mMeta->setInt32(kKeyHeight, mVideoSize.height);
+ mMeta->setInt32(kKeyStride, mVideoSize.width);
+ mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
+ return OK;
}
CameraSource::~CameraSource() {
@@ -183,10 +499,15 @@
void CameraSource::startCameraRecording() {
CHECK_EQ(OK, mCamera->startRecording());
+ CHECK(mCamera->recordingEnabled());
}
status_t CameraSource::start(MetaData *meta) {
CHECK(!mStarted);
+ if (mInitCheck != OK) {
+ LOGE("CameraSource is not initialized yet");
+ return mInitCheck;
+ }
char value[PROPERTY_VALUE_MAX];
if (property_get("media.stagefright.record-stats", value, NULL)
@@ -202,7 +523,6 @@
int64_t token = IPCThreadState::self()->clearCallingIdentity();
mCamera->setListener(new CameraSourceListener(this));
- startCameraRecording();
IPCThreadState::self()->restoreCallingIdentity(token);
mStarted = true;
@@ -228,7 +548,16 @@
mFramesBeingEncoded.size());
mFrameCompleteCondition.wait(mLock);
}
- mCamera = NULL;
+
+ LOGV("Disconnect camera");
+ if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
+ LOGV("Camera was cold when we started, stopping preview");
+ mCamera->stopPreview();
+ }
+ mCamera->unlock();
+ mCamera.clear();
+ mCamera = 0;
+ mCameraFlags = 0;
IPCThreadState::self()->restoreCallingIdentity(token);
if (mCollectStats) {
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index c1bc433..2f3f20b 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -37,57 +37,55 @@
namespace android {
// static
-CameraSourceTimeLapse *CameraSourceTimeLapse::Create(
- int64_t timeBetweenTimeLapseFrameCaptureUs,
- int32_t width, int32_t height,
- int32_t videoFrameRate) {
- sp<Camera> camera = Camera::connect(0);
+CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(
+ const sp<ICamera> &camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t videoFrameRate,
+ const sp<Surface>& surface,
+ int64_t timeBetweenTimeLapseFrameCaptureUs) {
- if (camera.get() == NULL) {
- return NULL;
+ CameraSourceTimeLapse *source = new
+ CameraSourceTimeLapse(camera, cameraId,
+ videoSize, videoFrameRate, surface,
+ timeBetweenTimeLapseFrameCaptureUs);
+
+ if (source != NULL) {
+ if (source->initCheck() != OK) {
+ delete source;
+ return NULL;
+ }
}
-
- return new CameraSourceTimeLapse(camera, timeBetweenTimeLapseFrameCaptureUs,
- width, height, videoFrameRate);
+ return source;
}
-// static
-CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(const sp<Camera> &camera,
- int64_t timeBetweenTimeLapseFrameCaptureUs,
- int32_t width, int32_t height,
- int32_t videoFrameRate) {
- if (camera.get() == NULL) {
- return NULL;
- }
-
- return new CameraSourceTimeLapse(camera, timeBetweenTimeLapseFrameCaptureUs,
- width, height, videoFrameRate);
-}
-
-CameraSourceTimeLapse::CameraSourceTimeLapse(const sp<Camera> &camera,
- int64_t timeBetweenTimeLapseFrameCaptureUs,
- int32_t width, int32_t height,
- int32_t videoFrameRate)
- : CameraSource(camera),
+CameraSourceTimeLapse::CameraSourceTimeLapse(
+ const sp<ICamera>& camera,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t videoFrameRate,
+ const sp<Surface>& surface,
+ int64_t timeBetweenTimeLapseFrameCaptureUs)
+ : CameraSource(camera, cameraId, videoSize, videoFrameRate, surface),
mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs),
mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
mLastTimeLapseFrameRealTimestampUs(0),
mSkipCurrentFrame(false) {
LOGV("starting time lapse mode");
- mVideoWidth = width;
- mVideoHeight = height;
+ mVideoWidth = videoSize.width;
+ mVideoHeight = videoSize.height;
- if (trySettingPreviewSize(width, height)) {
+ if (trySettingPreviewSize(videoSize.width, videoSize.height)) {
mUseStillCameraForTimeLapse = false;
} else {
// TODO: Add a check to see that mTimeBetweenTimeLapseFrameCaptureUs is greater
// than the fastest rate at which the still camera can take pictures.
mUseStillCameraForTimeLapse = true;
- CHECK(setPictureSizeToClosestSupported(width, height));
+ CHECK(setPictureSizeToClosestSupported(videoSize.width, videoSize.height));
mNeedCropping = computeCropRectangleOffset();
- mMeta->setInt32(kKeyWidth, width);
- mMeta->setInt32(kKeyHeight, height);
+ mMeta->setInt32(kKeyWidth, videoSize.width);
+ mMeta->setInt32(kKeyHeight, videoSize.height);
}
// Initialize quick stop variables.
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index a5341e3..c532d02 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -356,7 +356,8 @@
}
// static
-uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
+uint32_t OMXCodec::getComponentQuirks(
+ const char *componentName, bool isEncoder) {
uint32_t quirks = 0;
if (!strcmp(componentName, "OMX.Nvidia.amr.decoder") ||
@@ -421,6 +422,13 @@
quirks |= kInputBufferSizesAreBogus;
}
+ if (!strncmp(componentName, "OMX.SEC.", 8) && !isEncoder) {
+ // These output buffers contain no video data, just some
+ // opaque information that allows the overlay to display their
+ // contents.
+ quirks |= kOutputBuffersAreUnreadable;
+ }
+
return quirks;
}
@@ -507,13 +515,13 @@
LOGV("Successfully allocated OMX node '%s'", componentName);
sp<OMXCodec> codec = new OMXCodec(
- omx, node, getComponentQuirks(componentName),
+ omx, node, getComponentQuirks(componentName, createEncoder),
createEncoder, mime, componentName,
source);
observer->setCodec(codec);
- err = codec->configureCodec(meta);
+ err = codec->configureCodec(meta, flags);
if (err == OK) {
return codec;
@@ -526,93 +534,95 @@
return NULL;
}
-status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
- uint32_t type;
- const void *data;
- size_t size;
- if (meta->findData(kKeyESDS, &type, &data, &size)) {
- ESDS esds((const char *)data, size);
- CHECK_EQ(esds.InitCheck(), OK);
+status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
+ if (!(flags & kIgnoreCodecSpecificData)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
- &codec_specific_data, &codec_specific_data_size);
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
+ &codec_specific_data, &codec_specific_data_size);
- addCodecSpecificData(
- codec_specific_data, codec_specific_data_size);
- } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
- // Parse the AVCDecoderConfigurationRecord
+ addCodecSpecificData(
+ codec_specific_data, codec_specific_data_size);
+ } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ // Parse the AVCDecoderConfigurationRecord
- const uint8_t *ptr = (const uint8_t *)data;
+ const uint8_t *ptr = (const uint8_t *)data;
- CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
- uint8_t profile = ptr[1];
- uint8_t level = ptr[3];
+ CHECK(size >= 7);
+ CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ uint8_t profile = ptr[1];
+ uint8_t level = ptr[3];
- // There is decodable content out there that fails the following
- // assertion, let's be lenient for now...
- // CHECK((ptr[4] >> 2) == 0x3f); // reserved
+ // There is decodable content out there that fails the following
+ // assertion, let's be lenient for now...
+ // CHECK((ptr[4] >> 2) == 0x3f); // reserved
- size_t lengthSize = 1 + (ptr[4] & 3);
+ size_t lengthSize = 1 + (ptr[4] & 3);
- // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
- // violates it...
- // CHECK((ptr[5] >> 5) == 7); // reserved
+ // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
+ // violates it...
+ // CHECK((ptr[5] >> 5) == 7); // reserved
- size_t numSeqParameterSets = ptr[5] & 31;
+ size_t numSeqParameterSets = ptr[5] & 31;
- ptr += 6;
- size -= 6;
+ ptr += 6;
+ size -= 6;
- for (size_t i = 0; i < numSeqParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
+ for (size_t i = 0; i < numSeqParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
- ptr += 2;
- size -= 2;
+ ptr += 2;
+ size -= 2;
- CHECK(size >= length);
+ CHECK(size >= length);
- addCodecSpecificData(ptr, length);
+ addCodecSpecificData(ptr, length);
- ptr += length;
- size -= length;
- }
+ ptr += length;
+ size -= length;
+ }
- CHECK(size >= 1);
- size_t numPictureParameterSets = *ptr;
- ++ptr;
- --size;
+ CHECK(size >= 1);
+ size_t numPictureParameterSets = *ptr;
+ ++ptr;
+ --size;
- for (size_t i = 0; i < numPictureParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
+ for (size_t i = 0; i < numPictureParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
- ptr += 2;
- size -= 2;
+ ptr += 2;
+ size -= 2;
- CHECK(size >= length);
+ CHECK(size >= length);
- addCodecSpecificData(ptr, length);
+ addCodecSpecificData(ptr, length);
- ptr += length;
- size -= length;
- }
+ ptr += length;
+ size -= length;
+ }
- CODEC_LOGV(
- "AVC profile = %d (%s), level = %d",
- (int)profile, AVCProfileToString(profile), level);
+ CODEC_LOGV(
+ "AVC profile = %d (%s), level = %d",
+ (int)profile, AVCProfileToString(profile), level);
- if (!strcmp(mComponentName, "OMX.TI.Video.Decoder")
- && (profile != kAVCProfileBaseline || level > 30)) {
- // This stream exceeds the decoder's capabilities. The decoder
- // does not handle this gracefully and would clobber the heap
- // and wreak havoc instead...
+ if (!strcmp(mComponentName, "OMX.TI.Video.Decoder")
+ && (profile != kAVCProfileBaseline || level > 30)) {
+ // This stream exceeds the decoder's capabilities. The decoder
+ // does not handle this gracefully and would clobber the heap
+ // and wreak havoc instead...
- LOGE("Profile and/or level exceed the decoder's capabilities.");
- return ERROR_UNSUPPORTED;
+ LOGE("Profile and/or level exceed the decoder's capabilities.");
+ return ERROR_UNSUPPORTED;
+ }
}
}
@@ -1772,6 +1782,10 @@
buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
}
+ if (mQuirks & kOutputBuffersAreUnreadable) {
+ buffer->meta_data()->setInt32(kKeyIsUnreadable, true);
+ }
+
buffer->meta_data()->setPointer(
kKeyPlatformPrivate,
msg.u.extended_buffer_data.platform_private);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 9d89c20..af9c70c 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -159,6 +159,20 @@
LOGV("successfully decoded video frame.");
+ int32_t unreadable;
+ if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
+ && unreadable != 0) {
+ LOGV("video frame is unreadable, decoder does not give us access "
+ "to the video data.");
+
+ buffer->release();
+ buffer = NULL;
+
+ decoder->stop();
+
+ return NULL;
+ }
+
int64_t timeUs;
CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
if (thumbNailTime >= 0) {
diff --git a/media/libstagefright/httplive/LiveSource.cpp b/media/libstagefright/httplive/LiveSource.cpp
index 9103927..943a0fc 100644
--- a/media/libstagefright/httplive/LiveSource.cpp
+++ b/media/libstagefright/httplive/LiveSource.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
#define LOG_TAG "LiveSource"
#include <utils/Log.h>
@@ -22,18 +23,21 @@
#include "include/NuHTTPDataSource.h"
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaDebug.h>
namespace android {
LiveSource::LiveSource(const char *url)
- : mURL(url),
+ : mMasterURL(url),
mInitCheck(NO_INIT),
mPlaylistIndex(0),
mLastFetchTimeUs(-1),
mSource(new NuHTTPDataSource),
mSourceSize(0),
- mOffsetBias(0) {
+ mOffsetBias(0),
+ mSignalDiscontinuity(false),
+ mPrevBandwidthIndex(-1) {
if (switchToNext()) {
mInitCheck = OK;
}
@@ -46,21 +50,129 @@
return mInitCheck;
}
-bool LiveSource::loadPlaylist() {
+// static
+int LiveSource::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) {
+ if (a->mBandwidth < b->mBandwidth) {
+ return -1;
+ } else if (a->mBandwidth == b->mBandwidth) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static double uniformRand() {
+ return (double)rand() / RAND_MAX;
+}
+
+bool LiveSource::loadPlaylist(bool fetchMaster) {
+ mSignalDiscontinuity = false;
+
mPlaylist.clear();
mPlaylistIndex = 0;
- sp<ABuffer> buffer;
- status_t err = fetchM3U(mURL.c_str(), &buffer);
+ if (fetchMaster) {
+ mPrevBandwidthIndex = -1;
- if (err != OK) {
- return false;
+ sp<ABuffer> buffer;
+ status_t err = fetchM3U(mMasterURL.c_str(), &buffer);
+
+ if (err != OK) {
+ return false;
+ }
+
+ mPlaylist = new M3UParser(
+ mMasterURL.c_str(), buffer->data(), buffer->size());
+
+ if (mPlaylist->initCheck() != OK) {
+ return false;
+ }
+
+ if (mPlaylist->isVariantPlaylist()) {
+ for (size_t i = 0; i < mPlaylist->size(); ++i) {
+ BandwidthItem item;
+
+ sp<AMessage> meta;
+ mPlaylist->itemAt(i, &item.mURI, &meta);
+
+ unsigned long bandwidth;
+ CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth));
+
+ mBandwidthItems.push(item);
+ }
+ mPlaylist.clear();
+
+ // fall through
+ if (mBandwidthItems.size() == 0) {
+ return false;
+ }
+
+ mBandwidthItems.sort(SortByBandwidth);
+
+ for (size_t i = 0; i < mBandwidthItems.size(); ++i) {
+ const BandwidthItem &item = mBandwidthItems.itemAt(i);
+ LOGV("item #%d: %s", i, item.mURI.c_str());
+ }
+ }
}
- mPlaylist = new M3UParser(mURL.c_str(), buffer->data(), buffer->size());
+ if (mBandwidthItems.size() > 0) {
+#if 0
+ // Change bandwidth at random()
+ size_t index = uniformRand() * mBandwidthItems.size();
+#elif 0
+ // There's a 50% chance to stay on the current bandwidth and
+ // a 50% chance to switch to the next higher bandwidth (wrapping around
+ // to lowest)
+ size_t index;
+ if (uniformRand() < 0.5) {
+ index = mPrevBandwidthIndex < 0 ? 0 : (size_t)mPrevBandwidthIndex;
+ } else {
+ if (mPrevBandwidthIndex < 0) {
+ index = 0;
+ } else {
+ index = mPrevBandwidthIndex + 1;
+ if (index == mBandwidthItems.size()) {
+ index = 0;
+ }
+ }
+ }
+#else
+ // Stay on the lowest bandwidth available.
+ size_t index = 0; // Lowest bandwidth stream
+#endif
- if (mPlaylist->initCheck() != OK) {
- return false;
+ mURL = mBandwidthItems.editItemAt(index).mURI;
+
+ if (mPrevBandwidthIndex >= 0 && (size_t)mPrevBandwidthIndex != index) {
+ // If we switched streams because of bandwidth changes,
+ // we'll signal this discontinuity by inserting a
+ // special transport stream packet into the stream.
+ mSignalDiscontinuity = true;
+ }
+
+ mPrevBandwidthIndex = index;
+ } else {
+ mURL = mMasterURL;
+ }
+
+ if (mPlaylist == NULL) {
+ sp<ABuffer> buffer;
+ status_t err = fetchM3U(mURL.c_str(), &buffer);
+
+ if (err != OK) {
+ return false;
+ }
+
+ mPlaylist = new M3UParser(mURL.c_str(), buffer->data(), buffer->size());
+
+ if (mPlaylist->initCheck() != OK) {
+ return false;
+ }
+
+ if (mPlaylist->isVariantPlaylist()) {
+ return false;
+ }
}
if (!mPlaylist->meta()->findInt32(
@@ -79,6 +191,8 @@
}
bool LiveSource::switchToNext() {
+ mSignalDiscontinuity = false;
+
mOffsetBias += mSourceSize;
mSourceSize = 0;
@@ -87,7 +201,7 @@
int32_t nextSequenceNumber =
mPlaylistIndex + mFirstItemSequenceNumber;
- if (!loadPlaylist()) {
+ if (!loadPlaylist(mLastFetchTimeUs < 0)) {
LOGE("failed to reload playlist");
return false;
}
@@ -111,35 +225,62 @@
}
AString uri;
- CHECK(mPlaylist->itemAt(mPlaylistIndex, &uri));
- LOGI("switching to %s", uri.c_str());
+ sp<AMessage> itemMeta;
+ CHECK(mPlaylist->itemAt(mPlaylistIndex, &uri, &itemMeta));
+ LOGV("switching to %s", uri.c_str());
if (mSource->connect(uri.c_str()) != OK
|| mSource->getSize(&mSourceSize) != OK) {
return false;
}
+ int32_t val;
+ if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
+ mSignalDiscontinuity = true;
+ }
+
mPlaylistIndex++;
return true;
}
+static const ssize_t kHeaderSize = 188;
+
ssize_t LiveSource::readAt(off_t offset, void *data, size_t size) {
CHECK(offset >= mOffsetBias);
offset -= mOffsetBias;
- if (offset >= mSourceSize) {
- CHECK_EQ(offset, mSourceSize);
+ off_t delta = mSignalDiscontinuity ? kHeaderSize : 0;
- offset -= mSourceSize;
+ if (offset >= mSourceSize + delta) {
+ CHECK_EQ(offset, mSourceSize + delta);
+
+ offset -= mSourceSize + delta;
if (!switchToNext()) {
return ERROR_END_OF_STREAM;
}
+
+ if (mSignalDiscontinuity) {
+ LOGV("switchToNext changed streams");
+ } else {
+ LOGV("switchToNext stayed within the same stream");
+ }
+
+ mOffsetBias += delta;
+
+ delta = mSignalDiscontinuity ? kHeaderSize : 0;
+ }
+
+ if (offset < delta) {
+ size_t avail = delta - offset;
+ memset(data, 0, avail);
+ return avail;
}
size_t numRead = 0;
while (numRead < size) {
ssize_t n = mSource->readAt(
- offset + numRead, (uint8_t *)data + numRead, size - numRead);
+ offset + numRead - delta,
+ (uint8_t *)data + numRead, size - numRead);
if (n <= 0) {
break;
@@ -154,14 +295,24 @@
status_t LiveSource::fetchM3U(const char *url, sp<ABuffer> *out) {
*out = NULL;
- status_t err = mSource->connect(url);
+ sp<DataSource> source;
- if (err != OK) {
- return err;
+ if (!strncasecmp(url, "file://", 7)) {
+ source = new FileSource(url + 7);
+ } else {
+ CHECK(!strncasecmp(url, "http://", 7));
+
+ status_t err = mSource->connect(url);
+
+ if (err != OK) {
+ return err;
+ }
+
+ source = mSource;
}
off_t size;
- err = mSource->getSize(&size);
+ status_t err = source->getSize(&size);
if (err != OK) {
return err;
@@ -170,7 +321,7 @@
sp<ABuffer> buffer = new ABuffer(size);
size_t offset = 0;
while (offset < (size_t)size) {
- ssize_t n = mSource->readAt(
+ ssize_t n = source->readAt(
offset, buffer->data() + offset, size - offset);
if (n <= 0) {
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 17771c4..f6f7dbd 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -74,7 +74,8 @@
static bool MakeURL(const char *baseURL, const char *url, AString *out) {
out->clear();
- if (strncasecmp("http://", baseURL, 7)) {
+ if (strncasecmp("http://", baseURL, 7)
+ && strncasecmp("file://", baseURL, 7)) {
// Base URL must be absolute
return false;
}
@@ -128,7 +129,12 @@
line.setTo(&data[offset], offsetLF - offset);
}
- LOGI("#%s#", line.c_str());
+ // LOGI("#%s#", line.c_str());
+
+ if (line.empty()) {
+ offset = offsetLF + 1;
+ continue;
+ }
if (lineNo == 0 && line == "#EXTM3U") {
mIsExtM3U = true;
@@ -152,11 +158,20 @@
return ERROR_MALFORMED;
}
err = parseMetaData(line, &itemMeta, "duration");
+ } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
+ if (mIsVariantPlaylist) {
+ return ERROR_MALFORMED;
+ }
+ if (itemMeta == NULL) {
+ itemMeta = new AMessage;
+ }
+ itemMeta->setInt32("discontinuity", true);
} else if (line.startsWith("#EXT-X-STREAM-INF")) {
if (mMeta != NULL) {
return ERROR_MALFORMED;
}
mIsVariantPlaylist = true;
+ err = parseStreamInf(line, &itemMeta);
}
if (err != OK) {
@@ -215,6 +230,61 @@
}
// static
+status_t M3UParser::parseStreamInf(
+ const AString &line, sp<AMessage> *meta) {
+ ssize_t colonPos = line.find(":");
+
+ if (colonPos < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ size_t offset = colonPos + 1;
+
+ while (offset < line.size()) {
+ ssize_t end = line.find(",", offset);
+ if (end < 0) {
+ end = line.size();
+ }
+
+ AString attr(line, offset, end - offset);
+ attr.trim();
+
+ offset = end + 1;
+
+ ssize_t equalPos = attr.find("=");
+ if (equalPos < 0) {
+ continue;
+ }
+
+ AString key(attr, 0, equalPos);
+ key.trim();
+
+ AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
+ val.trim();
+
+ LOGV("key=%s value=%s", key.c_str(), val.c_str());
+
+ if (!strcasecmp("bandwidth", key.c_str())) {
+ const char *s = val.c_str();
+ char *end;
+ unsigned long x = strtoul(s, &end, 10);
+
+ if (end == s || *end != '\0') {
+ // malformed
+ continue;
+ }
+
+ if (meta->get() == NULL) {
+ *meta = new AMessage;
+ }
+ (*meta)->setInt32("bandwidth", x);
+ }
+ }
+
+ return OK;
+}
+
+// static
status_t M3UParser::ParseInt32(const char *s, int32_t *x) {
char *end;
long lval = strtol(s, &end, 10);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index e04a24d..6ebf4ce 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -222,6 +222,7 @@
status_t setDataSource_l(const sp<DataSource> &dataSource);
status_t setDataSource_l(const sp<MediaExtractor> &extractor);
void reset_l();
+ void partial_reset_l();
status_t seekTo_l(int64_t timeUs);
status_t pause_l(bool at_eos = false);
void initRenderer_l();
@@ -234,7 +235,7 @@
status_t initAudioDecoder();
void setVideoSource(sp<MediaSource> source);
- status_t initVideoDecoder();
+ status_t initVideoDecoder(uint32_t flags = 0);
void onStreamDone();
diff --git a/media/libstagefright/include/LiveSource.h b/media/libstagefright/include/LiveSource.h
index c55508c..5e89581 100644
--- a/media/libstagefright/include/LiveSource.h
+++ b/media/libstagefright/include/LiveSource.h
@@ -44,6 +44,13 @@
virtual ~LiveSource();
private:
+ struct BandwidthItem {
+ AString mURI;
+ unsigned long mBandwidth;
+ };
+ Vector<BandwidthItem> mBandwidthItems;
+
+ AString mMasterURL;
AString mURL;
status_t mInitCheck;
@@ -56,10 +63,15 @@
off_t mSourceSize;
off_t mOffsetBias;
+ bool mSignalDiscontinuity;
+ ssize_t mPrevBandwidthIndex;
+
status_t fetchM3U(const char *url, sp<ABuffer> *buffer);
+ static int SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b);
+
bool switchToNext();
- bool loadPlaylist();
+ bool loadPlaylist(bool fetchMaster);
DISALLOW_EVIL_CONSTRUCTORS(LiveSource);
};
diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h
index 36553de..69199ab 100644
--- a/media/libstagefright/include/M3UParser.h
+++ b/media/libstagefright/include/M3UParser.h
@@ -61,6 +61,9 @@
static status_t parseMetaData(
const AString &line, sp<AMessage> *meta, const char *key);
+ static status_t parseStreamInf(
+ const AString &line, sp<AMessage> *meta);
+
static status_t ParseInt32(const char *s, int32_t *x);
DISALLOW_EVIL_CONSTRUCTORS(M3UParser);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index bcaab9f..7c9b83a 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -49,6 +49,8 @@
unsigned pid, unsigned payload_unit_start_indicator,
ABitReader *br);
+ void signalDiscontinuity();
+
sp<MediaSource> getSource(SourceType type);
private:
@@ -67,6 +69,8 @@
unsigned payload_unit_start_indicator,
ABitReader *br);
+ void signalDiscontinuity();
+
sp<MediaSource> getSource(SourceType type);
protected:
@@ -124,6 +128,12 @@
return true;
}
+void ATSParser::Program::signalDiscontinuity() {
+ for (size_t i = 0; i < mStreams.size(); ++i) {
+ mStreams.editValueAt(i)->signalDiscontinuity();
+ }
+}
+
void ATSParser::Program::parseProgramMap(ABitReader *br) {
unsigned table_id = br->getBits(8);
LOGV(" table_id = %u", table_id);
@@ -271,6 +281,19 @@
mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
}
+void ATSParser::Stream::signalDiscontinuity() {
+ LOGV("Stream discontinuity");
+ mPayloadStarted = false;
+ mBuffer->setRange(0, 0);
+
+ mQueue.clear();
+
+ if (mStreamType == 0x1b && mSource != NULL) {
+ // Don't signal discontinuities on audio streams.
+ mSource->queueDiscontinuity();
+ }
+}
+
void ATSParser::Stream::parsePES(ABitReader *br) {
unsigned packet_startcode_prefix = br->getBits(24);
@@ -459,7 +482,10 @@
mSource = new AnotherPacketSource(meta);
mSource->queueAccessUnit(accessUnit);
}
- } else {
+ } else if (mQueue.getFormat() != NULL) {
+ // After a discontinuity we invalidate the queue's format
+ // and won't enqueue any access units to the source until
+ // the queue has reestablished the new format.
mSource->queueAccessUnit(accessUnit);
}
}
@@ -489,6 +515,12 @@
parseTS(&br);
}
+void ATSParser::signalDiscontinuity() {
+ for (size_t i = 0; i < mPrograms.size(); ++i) {
+ mPrograms.editItemAt(i)->signalDiscontinuity();
+ }
+}
+
void ATSParser::parseProgramAssociationTable(ABitReader *br) {
unsigned table_id = br->getBits(8);
LOGV(" table_id = %u", table_id);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 1e22e7b..9ec6d7b 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -33,6 +33,7 @@
ATSParser();
void feedTSPacket(const void *data, size_t size);
+ void signalDiscontinuity();
enum SourceType {
AVC_VIDEO,
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 3d51177..3f76820 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -59,21 +59,26 @@
if (!mBuffers.empty()) {
const sp<ABuffer> buffer = *mBuffers.begin();
-
- uint64_t timeUs;
- CHECK(buffer->meta()->findInt64(
- "time", (int64_t *)&timeUs));
-
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
- mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
-
- // hexdump(buffer->data(), buffer->size());
-
- memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
- *out = mediaBuffer;
-
mBuffers.erase(mBuffers.begin());
- return OK;
+
+ int32_t discontinuity;
+ if (buffer->meta()->findInt32("discontinuity", &discontinuity)
+ && discontinuity) {
+ return INFO_DISCONTINUITY;
+ } else {
+ uint64_t timeUs;
+ CHECK(buffer->meta()->findInt64(
+ "time", (int64_t *)&timeUs));
+
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
+ mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+ // hexdump(buffer->data(), buffer->size());
+
+ memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
+ *out = mediaBuffer;
+ return OK;
+ }
}
return mEOSResult;
@@ -91,6 +96,15 @@
mCondition.signal();
}
+void AnotherPacketSource::queueDiscontinuity() {
+ sp<ABuffer> buffer = new ABuffer(0);
+ buffer->meta()->setInt32("discontinuity", true);
+
+ Mutex::Autolock autoLock(mLock);
+ mBuffers.push_back(buffer);
+ mCondition.signal();
+}
+
void AnotherPacketSource::signalEOS(status_t result) {
CHECK(result != OK);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index ce83d21..6b43c4e 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -40,6 +40,7 @@
bool hasBufferAvailable(status_t *finalResult);
void queueAccessUnit(const sp<ABuffer> &buffer);
+ void queueDiscontinuity();
void signalEOS(status_t result);
protected:
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index d87040b..4a75ee4 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -115,6 +115,11 @@
return OK;
}
+void ElementaryStreamQueue::clear() {
+ mBuffer->setRange(0, 0);
+ mFormat.clear();
+}
+
status_t ElementaryStreamQueue::appendData(
const void *data, size_t size, int64_t timeUs) {
if (mBuffer == NULL || mBuffer->size() == 0) {
@@ -147,7 +152,7 @@
if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
neededSize = (neededSize + 65535) & ~65535;
- LOGI("resizing buffer to size %d", neededSize);
+ LOGV("resizing buffer to size %d", neededSize);
sp<ABuffer> buffer = new ABuffer(neededSize);
if (mBuffer != NULL) {
@@ -498,6 +503,8 @@
meta->setInt32(kKeyWidth, width);
meta->setInt32(kKeyHeight, height);
+ LOGI("found AVC codec config (%d x %d)", width, height);
+
return meta;
}
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index d2e87f2..246c390 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -35,6 +35,7 @@
ElementaryStreamQueue(Mode mode);
status_t appendData(const void *data, size_t size, int64_t timeUs);
+ void clear();
sp<ABuffer> dequeueAccessUnit();
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index c5257bb..0d96bd1 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -165,18 +165,26 @@
LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
}
+static bool isDiscontinuity(const uint8_t *data, ssize_t size) {
+ return size == 188 && data[0] == 0x00;
+}
+
status_t MPEG2TSExtractor::feedMore() {
Mutex::Autolock autoLock(mLock);
uint8_t packet[kTSPacketSize];
ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
- if (n < (ssize_t)kTSPacketSize) {
+ if (isDiscontinuity(packet, n)) {
+ LOGI("XXX discontinuity detected");
+ mParser->signalDiscontinuity();
+ } else if (n < (ssize_t)kTSPacketSize) {
return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
+ } else {
+ mParser->feedTSPacket(packet, kTSPacketSize);
}
- mOffset += kTSPacketSize;
- mParser->feedTSPacket(packet, kTSPacketSize);
+ mOffset += n;
return OK;
}
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index a63b744..a9d8426 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -135,6 +135,15 @@
* to specify this event flag in the requested event set.
*/
ALOOPER_EVENT_HANGUP = 1 << 3,
+
+ /**
+ * The file descriptor is invalid.
+ * For example, the file descriptor was closed prematurely.
+ *
+ * The looper always sends notifications about invalid file descriptors; it is not necessary
+ * to specify this event flag in the requested event set.
+ */
+ ALOOPER_EVENT_INVALID = 1 << 4,
};
/**
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_default.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_default.png
new file mode 100644
index 0000000..bf33c946
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_ime_default.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 6aee011..494dfa8 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -28,11 +28,11 @@
>
<ImageView
- class="com.android.systemui.statusbar.tablet.NotificationIconArea$MoreView"
android:id="@+id/expand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_sysbar_open"
+ android:background="@drawable/ic_sysbar_icon_bg"
android:paddingLeft="6dip"
android:onClick="notificationIconsClicked"
/>
@@ -100,8 +100,18 @@
android:background="@drawable/sysbar_hidenotification_handle"
android:layout_marginLeft="8dip"
/>
+ <com.android.systemui.statusbar.tablet.InputMethodButton
+ android:id="@+id/imeButton"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="8dip"
+ android:src="@drawable/ic_sysbar_ime_default"
+ android:background="@drawable/ic_sysbar_icon_bg"
+ android:visibility="visible"
+ />
</com.android.systemui.statusbar.tablet.NotificationIconArea>
+
<FrameLayout
android:id="@+id/ticker"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
index 16a3c17..faea3fc 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
@@ -51,7 +51,6 @@
import android.graphics.drawable.Drawable;
import android.graphics.PixelFormat;
import android.os.Bundle;
-import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
@@ -176,7 +175,6 @@
}
private class LocalCarouselViewHelper extends CarouselViewHelper {
- private Paint mPaint = new Paint();
private DetailTextureParameters mDetailParams = new DetailTextureParameters(10.0f, 20.0f);
public LocalCarouselViewHelper(Context context) {
@@ -315,7 +313,9 @@
} else {
info.matrix = null;
}
- mCarouselView.setTextureForItem(info.position, compositeBitmap(info));
+ // Force Carousel to request new textures for this item.
+ mCarouselView.setTextureForItem(info.position, null);
+ mCarouselView.setDetailTextureForItem(info.position, 0, 0, 0, 0, null);
} else {
if (DBG) Log.v(TAG, "Can't find view for id " + id);
}
@@ -351,10 +351,12 @@
final View decorView = getWindow().getDecorView();
getWindow().getDecorView().setBackgroundColor(0x80000000);
- setContentView(R.layout.recent_apps_activity);
-
if (mCarouselView == null) {
+ long t = System.currentTimeMillis();
+ setContentView(R.layout.recent_apps_activity);
+ long elapsed = System.currentTimeMillis() - t;
+ Log.v(TAG, "Recents layout took " + elapsed + "ms to load");
mLoadingBitmap = BitmapFactory.decodeResource(res, R.drawable.recent_rez_border);
mCarouselView = (CarouselView)findViewById(R.id.carousel);
mHelper = new LocalCarouselViewHelper(this);
@@ -423,7 +425,6 @@
if (DBG) Log.v(TAG, "*** RUNNING THUMBNAIL WAS NULL ***");
}
}
- mCarouselView.createCards(mActivityDescriptions.size());
}
private void updateRecentTasks() {
@@ -491,6 +492,14 @@
private void showCarousel(boolean show) {
if (show) {
+ mCarouselView.createCards(mActivityDescriptions.size());
+ for (int i = 1; i < mActivityDescriptions.size(); i++) {
+ // Force Carousel to update textures. Note we don't do this for the first item,
+ // since it will be updated when mThumbnailReceiver returns a thumbnail.
+ // TODO: only do this for apps that have changed.
+ mCarouselView.setTextureForItem(i, null);
+ mCarouselView.setDetailTextureForItem(i, 0, 0, 0, 0, null);
+ }
// Make carousel visible
mNoRecentsView.setVisibility(View.GONE);
mCarouselView.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
new file mode 100644
index 0000000..ba682b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tablet;
+
+import android.content.Context;
+import android.util.Slog;
+import android.view.View;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.server.InputMethodManagerService;
+
+public class InputMethodButton extends ImageView {
+
+ // other services we wish to talk to
+ InputMethodManager mImm;
+
+ public InputMethodButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // IME hookup
+ mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ // TODO: read the current icon & visibility state directly from the service
+
+ // TODO: register for notifications about changes to visibility & subtype from service
+
+ setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mImm.showInputMethodSubtypePicker();
+ }
+ });
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
index 29df28e..d024dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
@@ -46,6 +46,7 @@
import android.widget.TextView;
import android.view.View;
import android.view.Window;
+import android.view.WindowManager;
import android.util.Log;
import java.util.List;
@@ -102,6 +103,11 @@
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarIndeterminateVisibility(true);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ if (Environment.isExternalStorageRemovable()) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ }
+
setTitle(getString(com.android.internal.R.string.usb_storage_activity_title));
setContentView(com.android.internal.R.layout.usb_storage_activity);
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 3583ab9..1383354 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -214,6 +214,9 @@
}
class WaveViewMethods implements WaveView.OnTriggerListener {
+ private static final int WAIT_FOR_ANIMATION_TIMEOUT = 500;
+ private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
+
/** {@inheritDoc} */
public void onTrigger(View v, int whichHandle) {
if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) {
@@ -222,13 +225,17 @@
public void run() {
mCallback.goToUnlockScreen();
}
- }, 500);
+ }, WAIT_FOR_ANIMATION_TIMEOUT);
}
}
/** {@inheritDoc} */
public void onGrabbedStateChange(View v, int grabbedState) {
- mCallback.pokeWakelock();
+ if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) {
+ mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT);
+ } else {
+ mCallback.pokeWakelock();
+ }
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 33685ba..68e0e32 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -47,6 +47,7 @@
import android.provider.Settings;
import com.android.internal.R;
+import com.android.internal.app.ShutdownThread;
import com.android.internal.policy.PolicyManager;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.telephony.ITelephony;
@@ -128,6 +129,10 @@
static final boolean DEBUG_LAYOUT = false;
static final boolean SHOW_STARTING_ANIMATIONS = true;
static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
+
+ static final int LONG_PRESS_POWER_NOTHING = 0;
+ static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
+ static final int LONG_PRESS_POWER_SHUT_OFF = 2;
// wallpaper is at the bottom, though the window manager may move it.
static final int WALLPAPER_LAYER = 2;
@@ -224,6 +229,7 @@
boolean mDeskDockEnablesAccelerometer;
int mLidKeyboardAccessibility;
int mLidNavigationAccessibility;
+ int mLongPressOnPowerBehavior = -1;
boolean mScreenOn = false;
boolean mOrientationSensorEnabled = false;
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -467,10 +473,27 @@
Runnable mPowerLongPress = new Runnable() {
public void run() {
- mShouldTurnOffOnKeyUp = false;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- showGlobalActionsDialog();
+ // The context isn't read
+ if (mLongPressOnPowerBehavior < 0) {
+ mLongPressOnPowerBehavior = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnPowerBehavior);
+ }
+ switch (mLongPressOnPowerBehavior) {
+ case LONG_PRESS_POWER_NOTHING:
+ break;
+ case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+ mShouldTurnOffOnKeyUp = false;
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+ showGlobalActionsDialog();
+ break;
+ case LONG_PRESS_POWER_SHUT_OFF:
+ mShouldTurnOffOnKeyUp = false;
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+ ShutdownThread.shutdown(mContext, true);
+ break;
+ }
}
};
diff --git a/policy/src/com/android/internal/policy/impl/PowerDialog.java b/policy/src/com/android/internal/policy/impl/PowerDialog.java
deleted file mode 100644
index de35bd7..0000000
--- a/policy/src/com/android/internal/policy/impl/PowerDialog.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-
-import android.app.Dialog;
-import android.app.StatusBarManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.LocalPowerManager;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-
-import com.android.internal.app.ShutdownThread;
-import com.android.internal.telephony.ITelephony;
-import android.view.KeyEvent;
-import android.util.Log;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.View.OnClickListener;
-import android.view.View.OnKeyListener;
-import android.widget.Button;
-
-/**
- * @deprecated use {@link GlobalActions} instead.
- */
-public class PowerDialog extends Dialog implements OnClickListener,
- OnKeyListener {
- private static final String TAG = "PowerDialog";
-
- static private StatusBarManager sStatusBar;
- private Button mKeyguard;
- private Button mPower;
- private Button mRadioPower;
- private Button mSilent;
-
- private LocalPowerManager mPowerManager;
-
- public PowerDialog(Context context, LocalPowerManager powerManager) {
- super(context);
- mPowerManager = powerManager;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Context context = getContext();
-
- if (sStatusBar == null) {
- sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
- }
-
- setContentView(com.android.internal.R.layout.power_dialog);
-
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- if (!getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_sf_slowBlur)) {
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- }
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
- setTitle(context.getText(R.string.power_dialog));
-
- mKeyguard = (Button) findViewById(R.id.keyguard);
- mPower = (Button) findViewById(R.id.off);
- mRadioPower = (Button) findViewById(R.id.radio_power);
- mSilent = (Button) findViewById(R.id.silent);
-
- if (mKeyguard != null) {
- mKeyguard.setOnKeyListener(this);
- mKeyguard.setOnClickListener(this);
- }
- if (mPower != null) {
- mPower.setOnClickListener(this);
- }
- if (mRadioPower != null) {
- mRadioPower.setOnClickListener(this);
- }
- if (mSilent != null) {
- mSilent.setOnClickListener(this);
- // XXX: HACK for now hide the silent until we get mute support
- mSilent.setVisibility(View.GONE);
- }
-
- CharSequence text;
-
- // set the keyguard button's text
- text = context.getText(R.string.screen_lock);
- mKeyguard.setText(text);
- mKeyguard.requestFocus();
-
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (phone != null) {
- text = phone.isRadioOn() ? context
- .getText(R.string.turn_off_radio) : context
- .getText(R.string.turn_on_radio);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- mRadioPower.setText(text);
- }
-
- public void onClick(View v) {
- this.dismiss();
- if (v == mPower) {
- // shutdown by making sure radio and power are handled accordingly.
- ShutdownThread.shutdown(getContext(), true);
- } else if (v == mRadioPower) {
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (phone != null) {
- phone.toggleRadioOnOff();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- } else if (v == mSilent) {
- // do something
- } else if (v == mKeyguard) {
- if (v.isInTouchMode()) {
- // only in touch mode for the reasons explained in onKey.
- this.dismiss();
- mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1);
- }
- }
- }
-
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // The activate keyguard button needs to put the device to sleep on the
- // key up event. If we try to put it to sleep on the click or down
- // action
- // the the up action will cause the device to wake back up.
-
- // Log.i(TAG, "keyCode: " + keyCode + " action: " + event.getAction());
- if (keyCode != KeyEvent.KEYCODE_DPAD_CENTER
- || event.getAction() != KeyEvent.ACTION_UP) {
- // Log.i(TAG, "getting out of dodge...");
- return false;
- }
-
- // Log.i(TAG, "Clicked mKeyguard! dimissing dialog");
- this.dismiss();
- // Log.i(TAG, "onKey: turning off the screen...");
- // XXX: This is a hack for now
- mPowerManager.goToSleep(event.getEventTime() + 1);
- return true;
- }
-
- public void show() {
- super.show();
- Log.d(TAG, "show... disabling expand");
- sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
- }
-
- public void dismiss() {
- super.dismiss();
- Log.d(TAG, "dismiss... reenabling expand");
- sStatusBar.disable(StatusBarManager.DISABLE_NONE);
- }
-}
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index e088417..4e2f1e3 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -38,9 +38,11 @@
import android.text.format.Time;
import android.util.EventLog;
import android.util.Slog;
+import android.util.TimeUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@@ -456,25 +458,28 @@
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
+ final long now = System.currentTimeMillis();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
pw.println(" ");
pw.print(" Realtime wakeup (now=");
- pw.print(System.currentTimeMillis()); pw.println("):");
+ pw.print(sdf.format(new Date(now))); pw.println("):");
if (mRtcWakeupAlarms.size() > 0) {
- dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP");
+ dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now);
}
if (mRtcAlarms.size() > 0) {
- dumpAlarmList(pw, mRtcAlarms, " ", "RTC");
+ dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now);
}
}
if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
+ final long now = SystemClock.elapsedRealtime();
pw.println(" ");
pw.print(" Elapsed realtime wakeup (now=");
- pw.print(SystemClock.elapsedRealtime()); pw.println("):");
+ TimeUtils.formatDuration(now, pw); pw.println("):");
if (mElapsedRealtimeWakeupAlarms.size() > 0) {
- dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP");
+ dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now);
}
if (mElapsedRealtimeAlarms.size() > 0) {
- dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED");
+ dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
}
}
@@ -499,12 +504,13 @@
}
}
- private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label) {
+ private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
+ String prefix, String label, long now) {
for (int i=list.size()-1; i>=0; i--) {
Alarm a = list.get(i);
pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
pw.print(": "); pw.println(a);
- a.dump(pw, prefix + " ");
+ a.dump(pw, prefix + " ", now);
}
}
@@ -619,10 +625,9 @@
return sb.toString();
}
- public void dump(PrintWriter pw, String prefix)
- {
+ public void dump(PrintWriter pw, String prefix, long now) {
pw.print(prefix); pw.print("type="); pw.print(type);
- pw.print(" when="); pw.print(when);
+ pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
pw.print(" repeatInterval="); pw.print(repeatInterval);
pw.print(" count="); pw.println(count);
pw.print(prefix); pw.print("operation="); pw.println(operation);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index dc4194c..70bde01 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -84,6 +84,7 @@
import java.text.Collator;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -1567,14 +1568,15 @@
int lastInputMethodSubtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId);
if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
- final List<InputMethodInfo> immis = getEnabledInputMethodList();
- ArrayList<Integer> subtypeIds = new ArrayList<Integer>();
-
- if (immis == null) {
- return;
- }
-
synchronized (mMethodMap) {
+ final List<Pair<InputMethodInfo, ArrayList<String>>> immis =
+ mSettings.getEnabledInputMethodAndSubtypeListLocked();
+ ArrayList<Integer> subtypeIds = new ArrayList<Integer>();
+
+ if (immis == null || immis.size() == 0) {
+ return;
+ }
+
hideInputMethodMenuLocked();
int N = immis.size();
@@ -1583,32 +1585,38 @@
new TreeMap<CharSequence, Pair<InputMethodInfo, Integer>>(Collator.getInstance());
for (int i = 0; i < N; ++i) {
- InputMethodInfo property = immis.get(i);
+ InputMethodInfo property = immis.get(i).first;
+ final ArrayList<String> enabledSubtypeIds = immis.get(i).second;
+ HashSet<String> enabledSubtypeSet = new HashSet<String>();
+ for (String s : enabledSubtypeIds) {
+ enabledSubtypeSet.add(s);
+ }
if (property == null) {
continue;
}
- // TODO: Show only enabled subtypes
ArrayList<InputMethodSubtype> subtypes = property.getSubtypes();
CharSequence label = property.loadLabel(pm);
- if (showSubtypes && subtypes.size() > 0) {
+ if (showSubtypes && enabledSubtypeSet.size() > 0) {
for (int j = 0; j < subtypes.size(); ++j) {
InputMethodSubtype subtype = subtypes.get(j);
- CharSequence title;
- int nameResId = subtype.getNameResId();
- int modeResId = subtype.getModeResId();
- if (nameResId != 0) {
- title = pm.getText(property.getPackageName(), nameResId,
- property.getServiceInfo().applicationInfo);
- } else {
- CharSequence language = subtype.getLocale();
- CharSequence mode = modeResId == 0 ? null
- : pm.getText(property.getPackageName(), modeResId,
- property.getServiceInfo().applicationInfo);
- // TODO: Use more friendly Title and UI
- title = label + "," + (mode == null ? "" : mode) + ","
- + (language == null ? "" : language);
+ if (enabledSubtypeSet.contains(String.valueOf(subtype.hashCode()))) {
+ CharSequence title;
+ int nameResId = subtype.getNameResId();
+ int modeResId = subtype.getModeResId();
+ if (nameResId != 0) {
+ title = pm.getText(property.getPackageName(), nameResId,
+ property.getServiceInfo().applicationInfo);
+ } else {
+ CharSequence language = subtype.getLocale();
+ CharSequence mode = modeResId == 0 ? null
+ : pm.getText(property.getPackageName(), modeResId,
+ property.getServiceInfo().applicationInfo);
+ // TODO: Use more friendly Title and UI
+ title = label + "," + (mode == null ? "" : mode) + ","
+ + (language == null ? "" : language);
+ }
+ imMap.put(title, new Pair<InputMethodInfo, Integer>(property, j));
}
- imMap.put(title, new Pair<InputMethodInfo, Integer>(property, j));
}
} else {
imMap.put(label,
@@ -1678,6 +1686,20 @@
}
});
+ if (showSubtypes) {
+ mDialogBuilder.setPositiveButton(com.android.internal.R.string.more_item_label,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ showInputMethodAndSubtypeEnabler();
+ }
+ });
+ }
+ mDialogBuilder.setNegativeButton(com.android.internal.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ hideInputMethodMenu();
+ }
+ });
mSwitchingDialog = mDialogBuilder.create();
mSwitchingDialog.getWindow().setType(
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
@@ -1864,6 +1886,12 @@
getEnabledInputMethodsAndSubtypeListLocked());
}
+ public List<Pair<InputMethodInfo, ArrayList<String>>>
+ getEnabledInputMethodAndSubtypeListLocked() {
+ return createEnabledInputMethodAndSubtypeListLocked(
+ getEnabledInputMethodsAndSubtypeListLocked());
+ }
+
// At the initial boot, the settings for input methods are not set,
// so we need to enable IME in that case.
public void enableAllIMEsIfThereIsNoEnabledIME() {
@@ -1960,6 +1988,20 @@
return res;
}
+ private List<Pair<InputMethodInfo, ArrayList<String>>>
+ createEnabledInputMethodAndSubtypeListLocked(
+ List<Pair<String, ArrayList<String>>> imsList) {
+ final ArrayList<Pair<InputMethodInfo, ArrayList<String>>> res
+ = new ArrayList<Pair<InputMethodInfo, ArrayList<String>>>();
+ for (Pair<String, ArrayList<String>> ims : imsList) {
+ InputMethodInfo info = mMethodMap.get(ims.first);
+ if (info != null) {
+ res.add(new Pair<InputMethodInfo, ArrayList<String>>(info, ims.second));
+ }
+ }
+ return res;
+ }
+
private void putEnabledInputMethodsStr(String str) {
Settings.Secure.putString(mResolver, Settings.Secure.ENABLED_INPUT_METHODS, str);
mEnabledInputMethodsStrCache = str;
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 7870b06..295047c 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -79,8 +79,6 @@
private static final String VOLD_TAG = "VoldConnector";
- protected static final int MAX_OBBS = 8;
-
/*
* Internal vold volume state constants
*/
@@ -161,7 +159,6 @@
* Mounted OBB tracking information. Used to track the current state of all
* OBBs.
*/
- final private Map<Integer, Integer> mObbUidUsage = new HashMap<Integer, Integer>();
final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
@@ -172,8 +169,6 @@
this.token = token;
this.callerUid = callerUid;
mounted = false;
-
- getBinder().linkToDeath(this, 0);
}
// OBB source filename
@@ -198,7 +193,11 @@
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
}
- public void cleanUp() {
+ public void link() throws RemoteException {
+ getBinder().linkToDeath(this, 0);
+ }
+
+ public void unlink() {
getBinder().unlinkToDeath(this, 0);
}
@@ -226,7 +225,6 @@
private static final int OBB_MCS_BOUND = 2;
private static final int OBB_MCS_UNBIND = 3;
private static final int OBB_MCS_RECONNECT = 4;
- private static final int OBB_MCS_GIVE_UP = 5;
/*
* Default Container Service information
@@ -1602,12 +1600,6 @@
}
final int callerUid = Binder.getCallingUid();
-
- final Integer uidUsage = mObbUidUsage.get(callerUid);
- if (uidUsage != null && uidUsage > MAX_OBBS) {
- throw new IllegalStateException("Maximum number of OBBs mounted!");
- }
-
obbState = new ObbState(filename, token, callerUid);
addObbState(obbState);
}
@@ -1672,56 +1664,61 @@
Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
- private void addObbState(ObbState obbState) {
+ private void addObbState(ObbState obbState) throws RemoteException {
synchronized (mObbMounts) {
- List<ObbState> obbStates = mObbMounts.get(obbState.getBinder());
+ final IBinder binder = obbState.getBinder();
+ List<ObbState> obbStates = mObbMounts.get(binder);
+ final boolean unique;
+
if (obbStates == null) {
obbStates = new ArrayList<ObbState>();
- mObbMounts.put(obbState.getBinder(), obbStates);
- }
- obbStates.add(obbState);
- mObbPathToStateMap.put(obbState.filename, obbState);
-
- // Track the number of OBBs used by this UID.
- final int uid = obbState.callerUid;
- final Integer uidUsage = mObbUidUsage.get(uid);
- if (uidUsage == null) {
- mObbUidUsage.put(uid, 1);
+ mObbMounts.put(binder, obbStates);
+ unique = true;
} else {
- mObbUidUsage.put(uid, uidUsage + 1);
+ unique = obbStates.contains(obbState);
}
+
+ if (unique) {
+ obbStates.add(obbState);
+ try {
+ obbState.link();
+ } catch (RemoteException e) {
+ /*
+ * The binder died before we could link it, so clean up our
+ * state and return failure.
+ */
+ obbStates.remove(obbState);
+ if (obbStates.isEmpty()) {
+ mObbMounts.remove(binder);
+ }
+
+ // Rethrow the error so mountObb can get it
+ throw e;
+ }
+ }
+
+ mObbPathToStateMap.put(obbState.filename, obbState);
}
}
private void removeObbState(ObbState obbState) {
synchronized (mObbMounts) {
- final List<ObbState> obbStates = mObbMounts.get(obbState.getBinder());
+ final IBinder binder = obbState.getBinder();
+ final List<ObbState> obbStates = mObbMounts.get(binder);
if (obbStates != null) {
- obbStates.remove(obbState);
- }
- if (obbStates == null || obbStates.isEmpty()) {
- mObbMounts.remove(obbState.getBinder());
- obbState.cleanUp();
- }
- mObbPathToStateMap.remove(obbState.filename);
-
- // Track the number of OBBs used by this UID.
- final int uid = obbState.callerUid;
- final Integer uidUsage = mObbUidUsage.get(uid);
- if (uidUsage == null) {
- Slog.e(TAG, "Called removeObbState for UID that isn't in map: " + uid);
- } else {
- final int newUsage = uidUsage - 1;
- if (newUsage == 0) {
- mObbUidUsage.remove(uid);
- } else {
- mObbUidUsage.put(uid, newUsage);
+ if (obbStates.remove(obbState)) {
+ obbState.unlink();
+ }
+ if (obbStates.isEmpty()) {
+ mObbMounts.remove(binder);
}
}
+
+ mObbPathToStateMap.remove(obbState.filename);
}
}
- private void replaceObbState(ObbState oldObbState, ObbState newObbState) {
+ private void replaceObbState(ObbState oldObbState, ObbState newObbState) throws RemoteException {
synchronized (mObbMounts) {
removeObbState(oldObbState);
addObbState(newObbState);
@@ -1730,7 +1727,7 @@
private class ObbActionHandler extends Handler {
private boolean mBound = false;
- private List<ObbAction> mActions = new LinkedList<ObbAction>();
+ private final List<ObbAction> mActions = new LinkedList<ObbAction>();
ObbActionHandler(Looper l) {
super(l);
@@ -1740,7 +1737,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case OBB_RUN_ACTION: {
- ObbAction action = (ObbAction) msg.obj;
+ final ObbAction action = (ObbAction) msg.obj;
if (DEBUG_OBB)
Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
@@ -1756,15 +1753,9 @@
action.handleError();
return;
}
-
- mActions.add(action);
- break;
}
- // Once we bind to the service, the first
- // pending request will be processed.
mActions.add(action);
- mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
break;
}
case OBB_MCS_BOUND: {
@@ -1782,7 +1773,7 @@
}
mActions.clear();
} else if (mActions.size() > 0) {
- ObbAction action = mActions.get(0);
+ final ObbAction action = mActions.get(0);
if (action != null) {
action.execute(this);
}
@@ -1830,12 +1821,6 @@
}
break;
}
- case OBB_MCS_GIVE_UP: {
- if (DEBUG_OBB)
- Slog.i(TAG, "OBB_MCS_GIVE_UP");
- mActions.remove(0);
- break;
- }
}
}
@@ -1875,7 +1860,7 @@
mRetries++;
if (mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
- mObbActionHandler.sendEmptyMessage(OBB_MCS_GIVE_UP);
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
handleError();
return;
} else {
@@ -1892,6 +1877,7 @@
if (DEBUG_OBB)
Slog.d(TAG, "Error handling OBB action", e);
handleError();
+ mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d008c90..3084c16 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2998,84 +2998,6 @@
}
}
- final void decPersistentCountLocked(ProcessRecord app) {
- app.persistentActivities--;
- if (app.persistentActivities > 0) {
- // Still more of 'em...
- return;
- }
- if (app.persistent) {
- // Ah, but the application itself is persistent. Whatever!
- return;
- }
-
- // App is no longer persistent... make sure it and the ones
- // following it in the LRU list have the correc oom_adj.
- updateOomAdjLocked();
- }
-
- public void setPersistent(IBinder token, boolean isPersistent) {
- if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
- != PackageManager.PERMISSION_GRANTED) {
- String msg = "Permission Denial: setPersistent() from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
-
- synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
- return;
- }
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- ProcessRecord app = r.app;
-
- if (localLOGV) Slog.v(
- TAG, "Setting persistence " + isPersistent + ": " + r);
-
- if (isPersistent) {
- if (r.persistent) {
- // Okay okay, I heard you already!
- if (localLOGV) Slog.v(TAG, "Already persistent!");
- return;
- }
- r.persistent = true;
- app.persistentActivities++;
- if (localLOGV) Slog.v(TAG, "Num persistent now: " + app.persistentActivities);
- if (app.persistentActivities > 1) {
- // We aren't the first...
- if (localLOGV) Slog.v(TAG, "Not the first!");
- return;
- }
- if (app.persistent) {
- // This would be redundant.
- if (localLOGV) Slog.v(TAG, "App is persistent!");
- return;
- }
-
- // App is now persistent... make sure it and the ones
- // following it now have the correct oom_adj.
- final long origId = Binder.clearCallingIdentity();
- updateOomAdjLocked();
- Binder.restoreCallingIdentity(origId);
-
- } else {
- if (!r.persistent) {
- // Okay okay, I heard you already!
- return;
- }
- r.persistent = false;
- final long origId = Binder.clearCallingIdentity();
- decPersistentCountLocked(app);
- Binder.restoreCallingIdentity(origId);
-
- }
- }
- }
-
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer) {
int uid = Binder.getCallingUid();
@@ -11765,11 +11687,6 @@
adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
- } else if (app.persistentActivities > 0) {
- // Special persistent activities... shouldn't be used these days.
- adj = FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.adjType = "persistent";
} else if (app.curReceiver != null ||
(mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
// An app that is currently receiving a broadcast also
@@ -12493,8 +12410,7 @@
final ProcessRecord app = mLruProcesses.get(i);
if (app.persistent || app.services.size() != 0
- || app.curReceiver != null
- || app.persistentActivities > 0) {
+ || app.curReceiver != null) {
// Don't count processes holding services against our
// maximum process count.
if (localLOGV) Slog.v(
@@ -12559,8 +12475,7 @@
// Quit the application only if we have a state saved for
// all of its activities.
boolean canQuit = !app.persistent && app.curReceiver == null
- && app.services.size() == 0
- && app.persistentActivities == 0;
+ && app.services.size() == 0;
int NUMA = app.activities.size();
int j;
if (Config.LOGV) Slog.v(
@@ -12624,7 +12539,7 @@
// We can finish this one if we have its icicle saved and
// it is not persistent.
if ((r.haveState || !r.stateNotNeeded) && !r.visible
- && r.stopped && !r.persistent && !r.finishing) {
+ && r.stopped && !r.finishing) {
final int origSize = mMainStack.mLRUActivities.size();
r.stack.destroyActivityLocked(r, true);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 6bd89cc..47be6a2 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -96,7 +96,6 @@
int configChangeFlags; // which config values have changed
boolean keysPaused; // has key dispatching been paused for it?
boolean inHistory; // are we in the history stack?
- boolean persistent; // requested to be persistent?
int launchMode; // the launch mode activity attribute.
boolean visible; // does this activity's window need to be shown?
boolean waitingVisible; // true if waiting for a new act to become vis
@@ -161,7 +160,6 @@
pw.print(" finishing="); pw.println(finishing);
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
pw.print(" inHistory="); pw.print(inHistory);
- pw.print(" persistent="); pw.print(persistent);
pw.print(" immersive="); pw.print(immersive);
pw.print(" launchMode="); pw.println(launchMode);
pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
@@ -215,7 +213,6 @@
configDestroy = false;
keysPaused = false;
inHistory = false;
- persistent = false;
visible = true;
waitingVisible = false;
nowVisible = false;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 9ed1242..016ddcd 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -3151,9 +3151,6 @@
mService.mHandler.sendEmptyMessage(
ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
}
- if (r.persistent) {
- mService.decPersistentCountLocked(r.app);
- }
if (r.app.activities.size() == 0) {
// No longer have activities, so update location in
// LRU list.
@@ -3452,54 +3449,49 @@
return true;
}
- // If the activity isn't persistent, there is a chance we will
- // need to restart it.
- if (!r.persistent) {
-
- // Figure out what has changed between the two configurations.
- int changes = oldConfig.diff(newConfig);
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(r.info.configChanges)
- + ", newConfig=" + newConfig);
+ // Figure out what has changed between the two configurations.
+ int changes = oldConfig.diff(newConfig);
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
+ + Integer.toHexString(changes) + ", handles=0x"
+ + Integer.toHexString(r.info.configChanges)
+ + ", newConfig=" + newConfig);
+ }
+ if ((changes&(~r.info.configChanges)) != 0) {
+ // Aha, the activity isn't handling the change, so DIE DIE DIE.
+ r.configChangeFlags |= changes;
+ r.startFreezingScreenLocked(r.app, globalChanges);
+ if (r.app == null || r.app.thread == null) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is destroying non-running " + r);
+ destroyActivityLocked(r, true);
+ } else if (r.state == ActivityState.PAUSING) {
+ // A little annoying: we are waiting for this activity to
+ // finish pausing. Let's not do anything now, but just
+ // flag that it needs to be restarted when done pausing.
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is skipping already pausing " + r);
+ r.configDestroy = true;
+ return true;
+ } else if (r.state == ActivityState.RESUMED) {
+ // Try to optimize this case: the configuration is changing
+ // and we need to restart the top, resumed activity.
+ // Instead of doing the normal handshaking, just say
+ // "restart!".
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is restarting resumed " + r);
+ relaunchActivityLocked(r, r.configChangeFlags, true);
+ r.configChangeFlags = 0;
+ } else {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Switch is restarting non-resumed " + r);
+ relaunchActivityLocked(r, r.configChangeFlags, false);
+ r.configChangeFlags = 0;
}
- if ((changes&(~r.info.configChanges)) != 0) {
- // Aha, the activity isn't handling the change, so DIE DIE DIE.
- r.configChangeFlags |= changes;
- r.startFreezingScreenLocked(r.app, globalChanges);
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is destroying non-running " + r);
- destroyActivityLocked(r, true);
- } else if (r.state == ActivityState.PAUSING) {
- // A little annoying: we are waiting for this activity to
- // finish pausing. Let's not do anything now, but just
- // flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is skipping already pausing " + r);
- r.configDestroy = true;
- return true;
- } else if (r.state == ActivityState.RESUMED) {
- // Try to optimize this case: the configuration is changing
- // and we need to restart the top, resumed activity.
- // Instead of doing the normal handshaking, just say
- // "restart!".
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, true);
- r.configChangeFlags = 0;
- } else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
- "Switch is restarting non-resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, false);
- r.configChangeFlags = 0;
- }
-
- // All done... tell the caller we weren't able to keep this
- // activity around.
- return false;
- }
+
+ // All done... tell the caller we weren't able to keep this
+ // activity around.
+ return false;
}
// Default case: the activity can handle this new configuration, so
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index bac21b1..b268efa 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -84,8 +84,8 @@
pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
}
}
- pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.println(" ");
- pw.println(callerApp != null ? callerApp.toShortString() : "null");
+ pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.print(" ");
+ pw.print(callerApp != null ? callerApp.toShortString() : "null");
pw.print(" pid="); pw.print(callingPid);
pw.print(" uid="); pw.println(callingUid);
if (requiredPermission != null) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 404c6be..353ff6d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -115,7 +115,6 @@
Dialog anrDialog; // dialog being displayed due to app not resp.
boolean removed; // has app package been removed from device?
boolean debugging; // was app launched for debugging?
- int persistentActivities; // number of activities that are persistent
boolean waitedForDebugger; // has process show wait for debugger dialog?
Dialog waitDialog; // current wait for debugger dialog
@@ -181,8 +180,7 @@
pw.print(" foregroundServices="); pw.print(foregroundServices);
pw.print(" forcingToForeground="); pw.println(forcingToForeground);
pw.print(prefix); pw.print("persistent="); pw.print(persistent);
- pw.print(" removed="); pw.print(removed);
- pw.print(" persistentActivities="); pw.println(persistentActivities);
+ pw.print(" removed="); pw.println(removed);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.println(lruSeq);
if (!keeping) {
@@ -259,7 +257,6 @@
curAdj = setAdj = -100;
persistent = false;
removed = false;
- persistentActivities = 0;
}
public void setPid(int _pid) {
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index bfac346..0623f5b 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -113,7 +113,7 @@
private String[] mDnsServers;
private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
- private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
+ private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
// resampled each time we turn on tethering - used as cache for settings/config-val
private boolean mDunRequired; // configuration info - must use DUN apn on 3g
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index ff887e4..4af274b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -84,7 +84,9 @@
status_t HWComposer::commit() const {
int err = mHwc->set(mHwc, mDpy, mSur, mList);
- mList->flags &= ~HWC_GEOMETRY_CHANGED;
+ if (mList) {
+ mList->flags &= ~HWC_GEOMETRY_CHANGED;
+ }
return (status_t)err;
}
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index d668e88..4fb1e61 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -91,17 +91,21 @@
mMessages.remove(cur);
break;
}
- if (timeout>=0 && timeoutTime < now) {
- // we timed-out, return a NULL message
- result = 0;
- break;
- }
nextEventTime = result->when;
result = 0;
}
- if (timeout >= 0 && nextEventTime > 0) {
- if (nextEventTime > timeoutTime) {
+ if (timeout >= 0) {
+ if (timeoutTime < now) {
+ // we timed-out, return a NULL message
+ result = 0;
+ break;
+ }
+ if (nextEventTime > 0) {
+ if (nextEventTime > timeoutTime) {
+ nextEventTime = timeoutTime;
+ }
+ } else {
nextEventTime = timeoutTime;
}
}
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 09b7d05..7a026fa 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -1468,13 +1468,27 @@
*
*/
public Call getActiveFgCall() {
- for (Call call : mForegroundCalls) {
- if (call.getState() != Call.State.IDLE) {
+ Call call = getFirstNonIdleCall(mForegroundCalls);
+ if (call == null) {
+ call = (mDefaultPhone == null)
+ ? null
+ : mDefaultPhone.getForegroundCall();
+ }
+ return call;
+ }
+
+ // Returns the first call that is not in IDLE state. If both active calls
+ // and disconnecting/disconnected calls exist, return the first active call.
+ private Call getFirstNonIdleCall(List<Call> calls) {
+ Call result = null;
+ for (Call call : calls) {
+ if (!call.isIdle()) {
return call;
+ } else if (call.getState() != Call.State.IDLE) {
+ if (result == null) result = call;
}
}
- return (mDefaultPhone == null) ?
- null : mDefaultPhone.getForegroundCall();
+ return result;
}
/**
@@ -1491,13 +1505,13 @@
* Complete background calls list can be get by getBackgroundCalls()
*/
public Call getFirstActiveBgCall() {
- for (Call call : mBackgroundCalls) {
- if (call.getState() != Call.State.IDLE) {
- return call;
- }
+ Call call = getFirstNonIdleCall(mBackgroundCalls);
+ if (call == null) {
+ call = (mDefaultPhone == null)
+ ? null
+ : mDefaultPhone.getBackgroundCall();
}
- return (mDefaultPhone == null) ?
- null : mDefaultPhone.getBackgroundCall();
+ return call;
}
/**
@@ -1514,13 +1528,13 @@
* Complete ringing calls list can be get by getRingingCalls()
*/
public Call getFirstActiveRingingCall() {
- for (Call call : mRingingCalls) {
- if (!call.isIdle()) {
- return call;
- }
+ Call call = getFirstNonIdleCall(mRingingCalls);
+ if (call == null) {
+ call = (mDefaultPhone == null)
+ ? null
+ : mDefaultPhone.getRingingCall();
}
- return (mDefaultPhone == null) ?
- null : mDefaultPhone.getRingingCall();
+ return call;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 6e13690..c67b995 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -26,9 +26,9 @@
import android.text.TextUtils;
import android.telephony.TelephonyManager;
import android.telephony.PhoneNumberUtils;
-import android.util.Config;
import android.util.Log;
+
/**
* Looks up caller information for the given phone number.
*
@@ -36,6 +36,7 @@
*/
public class CallerInfo {
private static final String TAG = "CallerInfo";
+ private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
public static final String UNKNOWN_NUMBER = "-1";
public static final String PRIVATE_NUMBER = "-2";
@@ -129,7 +130,7 @@
info.isCachedPhotoCurrent = false;
info.contactExists = false;
- if (Config.LOGV) Log.v(TAG, "construct callerInfo from cursor");
+ if (VDBG) Log.v(TAG, "construct callerInfo from cursor");
if (cursor != null) {
if (cursor.moveToFirst()) {
@@ -173,31 +174,30 @@
// Look for the person ID.
// TODO: This is pretty ugly now, see bug 2269240 for
- // more details. With tel: URI the contact id is in
- // col "_id" while when we use a
- // content://contacts/data/phones URI, the contact id
- // is col "contact_id". As a work around we use the
- // type of the contact url to figure out which column
- // we should look at to get the contact_id.
-
- final String mimeType = context.getContentResolver().getType(contactRef);
+ // more details. The column to use depends upon the type of URL,
+ // for content://com.android.contacts/data/phones the "contact_id"
+ // column is used. For content/com.andriod.contacts/phone_lookup"
+ // the "_ID" column is used. If it is neither we leave columnIndex
+ // at -1 and no person ID will be available.
columnIndex = -1;
- if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
- // content://com.android.contacts/data/phones URL
+ String url = contactRef.toString();
+ if (url.startsWith("content://com.android.contacts/data/phones")) {
+ if (VDBG) Log.v(TAG,
+ "URL path starts with 'data/phones' using RawContacts.CONTACT_ID");
columnIndex = cursor.getColumnIndex(RawContacts.CONTACT_ID);
- } else {
- // content://com.android.contacts/phone_lookup URL
- // TODO: mime type is null here so we cannot test
- // if we have the right url type. phone_lookup URL
- // should resolve to a mime type.
+ } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
+ if (VDBG) Log.v(TAG,
+ "URL path starts with 'phone_lookup' using PhoneLookup._ID");
columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
+ } else {
+ Log.e(TAG, "Bad contact URL '" + url + "'");
}
if (columnIndex != -1) {
info.person_id = cursor.getLong(columnIndex);
} else {
- Log.e(TAG, "Column missing for " + contactRef);
+ Log.e(TAG, "person_id column missing for " + contactRef);
}
// look for the custom ringtone, create from the string stored
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 83ad552..6332415 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -358,8 +358,14 @@
EVENT_SIM_RECORDS_LOADED, null);
mNeedToRegForSimLoaded = false;
}
- // restore the previous network selection.
- phone.restoreSavedNetworkSelection(null);
+
+ boolean skipRestoringSelection = phone.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.skip_restoring_network_selection);
+
+ if (!skipRestoringSelection) {
+ // restore the previous network selection.
+ phone.restoreSavedNetworkSelection(null);
+ }
pollState();
// Signal strength polling stops when radio is off
queueNextSignalStrengthPoll();
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 6ed9295..878d30c 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -810,7 +810,10 @@
} catch (SipException e) {
throw new CallStateException("hangup(): " + e);
} finally {
- mAdapter.onCallEnded(DisconnectCause.LOCAL);
+ mAdapter.onCallEnded(((mState == Call.State.INCOMING)
+ || (mState == Call.State.WAITING))
+ ? DisconnectCause.INCOMING_REJECTED
+ : DisconnectCause.LOCAL);
}
}
}
diff --git a/tests/CoreTests/android/core/NIOTest.java b/tests/CoreTests/android/core/NIOTest.java
index fd279ca..9476d07 100644
--- a/tests/CoreTests/android/core/NIOTest.java
+++ b/tests/CoreTests/android/core/NIOTest.java
@@ -40,27 +40,31 @@
}
@SmallTest
- public void testNIO() throws Exception {
- ByteBuffer b;
-
+ public void testNIO_byte_array() throws Exception {
// Test byte array-based buffer
- b = ByteBuffer.allocate(12);
- byteBufferTest(b);
+ byteBufferTest(ByteBuffer.allocate(12));
+ }
+ public void testNIO_direct() throws Exception {
// Test native heap-allocated buffer
- b = ByteBuffer.allocateDirect(12);
- byteBufferTest(b);
+ byteBufferTest(ByteBuffer.allocateDirect(12));
+ }
+ public void testNIO_short_array() throws Exception {
// Test short array-based buffer
short[] shortArray = new short[8];
ShortBuffer sb = ShortBuffer.wrap(shortArray);
shortBufferTest(sb);
+ }
+ public void testNIO_int_array() throws Exception {
// Test int array-based buffer
int[] intArray = new int[8];
IntBuffer ib = IntBuffer.wrap(intArray);
intBufferTest(ib);
+ }
+ public void testNIO_float_array() throws Exception {
// Test float array-based buffer
float[] floatArray = new float[8];
FloatBuffer fb = FloatBuffer.wrap(floatArray);
@@ -70,6 +74,12 @@
private void byteBufferTest(ByteBuffer b) {
checkBuffer(b);
+ // Duplicate buffers revert to big-endian.
+ b.order(ByteOrder.LITTLE_ENDIAN);
+ ByteBuffer dupe = b.duplicate();
+ assertEquals(ByteOrder.BIG_ENDIAN, dupe.order());
+ b.order(ByteOrder.BIG_ENDIAN);
+
// Bounds checks
try {
b.put(-1, (byte) 0);
@@ -272,9 +282,9 @@
// Check 'getFloat'
b.order(ByteOrder.LITTLE_ENDIAN);
b.position(0);
- assertEquals(0xA3A2A1A0, Float.floatToIntBits(b.getFloat()));
- assertEquals(0xA7A6A5A4, Float.floatToIntBits(b.getFloat()));
- assertEquals(0xABAAA9A8, Float.floatToIntBits(b.getFloat()));
+ assertEquals(0xA3A2A1A0, Float.floatToRawIntBits(b.getFloat()));
+ assertEquals(0xA7A6A5A4, Float.floatToRawIntBits(b.getFloat()));
+ assertEquals(0xABAAA9A8, Float.floatToRawIntBits(b.getFloat()));
try {
b.getFloat();
fail("expected exception not thrown");
@@ -284,9 +294,9 @@
b.order(ByteOrder.BIG_ENDIAN);
b.position(0);
- assertEquals(0xA0A1A2A3, Float.floatToIntBits(b.getFloat()));
- assertEquals(0xA4A5A6A7, Float.floatToIntBits(b.getFloat()));
- assertEquals(0xA8A9AAAB, Float.floatToIntBits(b.getFloat()));
+ assertEquals(0xA0A1A2A3, Float.floatToRawIntBits(b.getFloat()));
+ assertEquals(0xA4A5A6A7, Float.floatToRawIntBits(b.getFloat()));
+ assertEquals(0xA8A9AAAB, Float.floatToRawIntBits(b.getFloat()));
try {
b.getFloat();
fail("expected exception not thrown");
@@ -296,8 +306,8 @@
// Check 'getDouble(int position)'
b.order(ByteOrder.LITTLE_ENDIAN);
- assertEquals(0xA7A6A5A4A3A2A1A0L, Double.doubleToLongBits(b.getDouble(0)));
- assertEquals(0xA8A7A6A5A4A3A2A1L, Double.doubleToLongBits(b.getDouble(1)));
+ assertEquals(0xA7A6A5A4A3A2A1A0L, Double.doubleToRawLongBits(b.getDouble(0)));
+ assertEquals(0xA8A7A6A5A4A3A2A1L, Double.doubleToRawLongBits(b.getDouble(1)));
try {
b.getDouble(-1);
fail("expected exception not thrown");
@@ -312,8 +322,8 @@
}
b.order(ByteOrder.BIG_ENDIAN);
- assertEquals(0xA0A1A2A3A4A5A6A7L, Double.doubleToLongBits(b.getDouble(0)));
- assertEquals(0xA1A2A3A4A5A6A7A8L, Double.doubleToLongBits(b.getDouble(1)));
+ assertEquals(0xA0A1A2A3A4A5A6A7L, Double.doubleToRawLongBits(b.getDouble(0)));
+ assertEquals(0xA1A2A3A4A5A6A7A8L, Double.doubleToRawLongBits(b.getDouble(1)));
try {
b.getDouble(-1);
fail("expected exception not thrown");
@@ -333,6 +343,9 @@
b.order(ByteOrder.LITTLE_ENDIAN);
bb = b.slice();
assertEquals(4, bb.capacity());
+ assertEquals(ByteOrder.BIG_ENDIAN, bb.order());
+ assertEquals(0xA1A2A3A4, bb.getInt(0));
+ bb.order(ByteOrder.LITTLE_ENDIAN);
assertEquals(0xA4A3A2A1, bb.getInt(0));
bb.order(ByteOrder.LITTLE_ENDIAN);
@@ -370,14 +383,14 @@
checkBuffer(fb);
assertEquals(1, fb.capacity());
- assertEquals(0xA4A3A2A1, Float.floatToIntBits(fb.get()));
+ assertEquals(0xA4A3A2A1, Float.floatToRawIntBits(fb.get()));
bb.order(ByteOrder.BIG_ENDIAN);
fb = bb.asFloatBuffer();
checkBuffer(fb);
assertEquals(1, fb.capacity());
- assertEquals(0xA1A2A3A4, Float.floatToIntBits(fb.get()));
+ assertEquals(0xA1A2A3A4, Float.floatToRawIntBits(fb.get()));
}
private void shortBufferTest(ShortBuffer sb) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
index 769bfdd..8fa626b 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
@@ -18,11 +18,16 @@
import android.app.Activity;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
+import android.graphics.RadialGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
+import android.graphics.SweepGradient;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
@@ -36,8 +41,13 @@
super.onCreate(savedInstanceState);
final FrameLayout layout = new FrameLayout(this);
+
final ShadersView shadersView = new ShadersView(this);
final GradientView gradientView = new GradientView(this);
+ final RadialGradientView radialGradientView = new RadialGradientView(this);
+ final SweepGradientView sweepGradientView = new SweepGradientView(this);
+ final BitmapView bitmapView = new BitmapView(this);
+
final SeekBar rotateView = new SeekBar(this);
rotateView.setMax(360);
rotateView.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@@ -51,13 +61,29 @@
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- gradientView.setRotationY((float)progress);
+ gradientView.setRotationY((float) progress);
+ radialGradientView.setRotationX((float) progress);
+ sweepGradientView.setRotationY((float) progress);
+ bitmapView.setRotationX((float) progress);
}
});
layout.addView(shadersView);
layout.addView(gradientView, new FrameLayout.LayoutParams(
200, 200, Gravity.CENTER));
+
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER);
+ lp.setMargins(220, 0, 0, 0);
+ layout.addView(radialGradientView, lp);
+
+ lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER);
+ lp.setMargins(440, 0, 0, 0);
+ layout.addView(sweepGradientView, lp);
+
+ lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER);
+ lp.setMargins(220, -220, 0, 0);
+ layout.addView(bitmapView, lp);
+
layout.addView(rotateView, new FrameLayout.LayoutParams(
300, FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
@@ -65,6 +91,32 @@
setContentView(layout);
}
+ static class BitmapView extends View {
+ private final Paint mPaint;
+
+ BitmapView(Context c) {
+ super(c);
+
+ Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+ BitmapShader shader = new BitmapShader(texture, Shader.TileMode.REPEAT,
+ Shader.TileMode.REPEAT);
+ mPaint = new Paint();
+ mPaint.setShader(shader);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(200, 200);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint);
+ }
+ }
+
static class GradientView extends View {
private final Paint mPaint;
@@ -90,6 +142,55 @@
}
}
+ static class RadialGradientView extends View {
+ private final Paint mPaint;
+
+ RadialGradientView(Context c) {
+ super(c);
+
+ RadialGradient gradient = new RadialGradient(0.0f, 0.0f, 100.0f, 0xff000000, 0xffffffff,
+ Shader.TileMode.MIRROR);
+ mPaint = new Paint();
+ mPaint.setShader(gradient);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(200, 200);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint);
+ }
+ }
+
+ static class SweepGradientView extends View {
+ private final Paint mPaint;
+
+ SweepGradientView(Context c) {
+ super(c);
+
+ SweepGradient gradient = new SweepGradient(100.0f, 100.0f, 0xff000000, 0xffffffff);
+ mPaint = new Paint();
+ mPaint.setShader(gradient);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(200, 200);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint);
+ }
+ }
+
static class ShadersView extends View {
private final Paint mPaint;
private final float mDrawWidth;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index 58b1b6c..f501459 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -246,8 +246,8 @@
BridgeXmlBlockParser parser = null;
if (set instanceof BridgeXmlBlockParser) {
parser = (BridgeXmlBlockParser)set;
- } else {
- // reall this should not be happening since its instantiated in Bridge
+ } else if (set != null) { // null parser is ok
+ // really this should not be happening since its instantiated in Bridge
mLogger.error("Parser is not a BridgeXmlBlockParser!");
return null;
}
@@ -256,13 +256,16 @@
TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes);
BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
- parser.isPlatformFile());
+ parser != null ? parser.isPlatformFile() : true);
// resolve the defStyleAttr value into a IStyleResourceValue
IStyleResourceValue defStyleValues = null;
// look for a custom style.
- String customStyle = parser.getAttributeValue(null /* namespace*/, "style");
+ String customStyle = null;
+ if (parser != null) {
+ customStyle = parser.getAttributeValue(null /* namespace*/, "style");
+ }
if (customStyle != null) {
IResourceValue item = findResValue(customStyle);
@@ -309,7 +312,10 @@
int index = styleAttribute.getKey().intValue();
String name = styleAttribute.getValue();
- String value = parser.getAttributeValue(namespace, name);
+ String value = null;
+ if (parser != null) {
+ value = parser.getAttributeValue(namespace, name);
+ }
// if there's no direct value for this attribute in the XML, we look for default
// values in the widget defStyle, and then in the theme.
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index 80c35fb..8c32aa0 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -65,6 +65,13 @@
public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
/**
+ * Action to broadcast when SipService is up.
+ * Internal use only.
+ * @hide
+ */
+ public static final String ACTION_SIP_SERVICE_UP =
+ "android.net.sip.SIP_SERVICE_UP";
+ /**
* Action string for the incoming call intent for the Phone app.
* Internal use only.
* @hide
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index a7c61e5..1fa2400 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -100,6 +100,7 @@
public static void start(Context context) {
if (SipManager.isApiSupported(context)) {
ServiceManager.addService("sip", new SipService(context));
+ context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
Log.i(TAG, "SIP service started");
}
}
@@ -825,11 +826,13 @@
synchronized (SipService.this) {
if (notCurrentSession(session)) return;
- if (errorCode == SipErrorCode.INVALID_CREDENTIALS) {
- if (DEBUG) Log.d(TAG, " pause auto-registration");
- stop();
- } else {
- onError();
+ switch (errorCode) {
+ case SipErrorCode.INVALID_CREDENTIALS:
+ case SipErrorCode.SERVER_UNREACHABLE:
+ if (DEBUG) Log.d(TAG, " pause auto-registration");
+ stop();
+ default:
+ restartLater();
}
mErrorCode = errorCode;
@@ -846,11 +849,11 @@
mErrorCode = SipErrorCode.TIME_OUT;
mProxy.onRegistrationTimeout(session);
- onError();
+ restartLater();
}
}
- private void onError() {
+ private void restartLater() {
mRegistered = false;
restart(backoffDuration());
if (mKeepAliveProcess != null) {
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 37fffa8..57b3710 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -96,8 +96,6 @@
private SipStack mSipStack;
private SipHelper mSipHelper;
- private String mLastNonce;
- private int mRPort;
// session that processes INVITE requests
private SipSessionImpl mCallReceiverSession;
@@ -150,7 +148,6 @@
Log.d(TAG, " start stack for " + myself.getUriString());
stack.start();
- mLastNonce = null;
mCallReceiverSession = null;
mSessionMap.clear();
}
@@ -366,8 +363,12 @@
ClientTransaction mClientTransaction;
String mPeerSessionDescription;
boolean mInCall;
- boolean mReRegisterFlag = false;
SessionTimer mTimer;
+ int mAuthenticationRetryCount;
+
+ // for registration
+ boolean mReRegisterFlag = false;
+ int mRPort;
// lightweight timer
class SessionTimer {
@@ -417,6 +418,8 @@
mState = SipSession.State.READY_TO_CALL;
mInviteReceived = null;
mPeerSessionDescription = null;
+ mRPort = 0;
+ mAuthenticationRetryCount = 0;
if (mDialog != null) mDialog.delete();
mDialog = null;
@@ -799,22 +802,10 @@
onRegistrationDone((state == SipSession.State.REGISTERING)
? getExpiryTime(((ResponseEvent) evt).getResponse())
: -1);
- mLastNonce = null;
- mRPort = 0;
return true;
case Response.UNAUTHORIZED:
case Response.PROXY_AUTHENTICATION_REQUIRED:
- if (!handleAuthentication(event)) {
- if (mLastNonce == null) {
- onRegistrationFailed(SipErrorCode.SERVER_ERROR,
- "server does not provide challenge");
- } else {
- Log.v(TAG, "Incorrect username/password");
- onRegistrationFailed(
- SipErrorCode.INVALID_CREDENTIALS,
- "incorrect username or password");
- }
- }
+ handleAuthentication(event);
return true;
default:
if (statusCode >= 500) {
@@ -830,16 +821,24 @@
throws SipException {
Response response = event.getResponse();
String nonce = getNonceFromResponse(response);
- if (((nonce != null) && nonce.equals(mLastNonce)) ||
- (nonce == null)) {
- mLastNonce = nonce;
+ if (nonce == null) {
+ onError(SipErrorCode.SERVER_ERROR,
+ "server does not provide challenge");
return false;
- } else {
+ } else if (mAuthenticationRetryCount < 2) {
mClientTransaction = mSipHelper.handleChallenge(
event, getAccountManager());
mDialog = mClientTransaction.getDialog();
- mLastNonce = nonce;
+ mAuthenticationRetryCount++;
+ if (isLoggable(this, event)) {
+ Log.d(TAG, " authentication retry count="
+ + mAuthenticationRetryCount);
+ }
return true;
+ } else {
+ onError(SipErrorCode.INVALID_CREDENTIALS,
+ "incorrect username or password");
+ return false;
}
}
@@ -995,12 +994,6 @@
getRealmFromResponse(response));
} else if (handleAuthentication(event)) {
addSipSession(this);
- } else if (mLastNonce == null) {
- onError(SipErrorCode.SERVER_ERROR,
- "server does not provide challenge");
- } else {
- onError(SipErrorCode.INVALID_CREDENTIALS,
- "incorrect username or password");
}
return true;
case Response.REQUEST_PENDING:
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
index 84c7166..72ee44e 100644
--- a/voip/jni/rtp/AmrCodec.cpp
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -73,7 +73,7 @@
}
// Handle mode-set and octet-align.
- const char *modes = strcasestr(fmtp, "mode-set=");
+ char *modes = (char*)strcasestr(fmtp, "mode-set=");
if (modes) {
mMode = 0;
mModeSet = 0;
diff --git a/voip/jni/rtp/EchoSuppressor.cpp b/voip/jni/rtp/EchoSuppressor.cpp
index 2ceebdc..fbeb315 100644
--- a/voip/jni/rtp/EchoSuppressor.cpp
+++ b/voip/jni/rtp/EchoSuppressor.cpp
@@ -15,6 +15,7 @@
*/
#include <stdio.h>
+#include <string.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
@@ -157,11 +158,12 @@
if (correlation > 0.3f) {
float factor = 1.0f - correlation;
factor *= factor;
+ factor /= 2.0; // suppress harder
for (int i = 0; i < mSampleCount; ++i) {
recorded[i] *= factor;
}
}
-// LOGI("latency %5d, correlation %.10f", latency, correlation);
+ //LOGI("latency %5d, correlation %.10f", latency, correlation);
// Increase RecordOffset.
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 9634157..be5fab4 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -20,6 +20,9 @@
import android.content.Context;
import android.content.Intent;
import android.net.DhcpInfo;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkUtils;
import android.net.ProxyProperties;
import android.net.wifi.WifiConfiguration.IpAssignment;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -34,13 +37,18 @@
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
+import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.BitSet;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
/**
@@ -61,13 +69,10 @@
* ..
*
* (key, value) pairs for a given network are grouped together and can
- * be in any order. A "EOS" at the end of a set of (key, value) pairs
+ * be in any order. A EOS at the end of a set of (key, value) pairs
* indicates that the next set of (key, value) pairs are for a new
- * network. A network is identified by a unique "id". If there is no
- * "id" key in the (key, value) pairs, the data is discarded. An IP
- * configuration includes the keys - "ipAssignment", "ipAddress", "gateway",
- * "netmask", "dns1" and "dns2". A proxy configuration includes "proxySettings",
- * "proxyHost", "proxyPort" and "exclusionList"
+ * network. A network is identified by a unique ID_KEY. If there is no
+ * ID_KEY in the (key, value) pairs, the data is discarded.
*
* An invalid version on read would result in discarding the contents of
* the file. On the next write, the latest version is written to file.
@@ -118,6 +123,18 @@
private static final int IPCONFIG_FILE_VERSION = 1;
+ /* IP and proxy configuration keys */
+ private static final String ID_KEY = "id";
+ private static final String IP_ASSIGNMENT_KEY = "ipAssignment";
+ private static final String LINK_ADDRESS_KEY = "linkAddress";
+ private static final String GATEWAY_KEY = "gateway";
+ private static final String DNS_KEY = "dns";
+ private static final String PROXY_SETTINGS_KEY = "proxySettings";
+ private static final String PROXY_HOST_KEY = "proxyHost";
+ private static final String PROXY_PORT_KEY = "proxyPort";
+ private static final String EXCLUSION_LIST_KEY = "exclusionList";
+ private static final String EOS = "eos";
+
/**
* Initialize context, fetch the list of configured networks
* and enable all stored networks in supplicant.
@@ -370,25 +387,61 @@
}
/**
- * Fetch the IP configuration for a given network id
+ * Fetch the link properties for a given network id
*/
- static DhcpInfo getIpConfiguration(int netId) {
+ static LinkProperties getLinkProperties(int netId) {
synchronized (sConfiguredNetworks) {
WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null) return new DhcpInfo(config.ipConfig);
+ if (config != null) return new LinkProperties(config.linkProperties);
}
return null;
}
/**
+ * get IP configuration for a given network id
+ * TODO: We cannot handle IPv6 addresses for configuration
+ * right now until NetworkUtils is fixed. When we do
+ * that, we should remove handling DhcpInfo and move
+ * to using LinkProperties
+ */
+ static DhcpInfo getIpConfiguration(int netId) {
+ DhcpInfo dhcpInfo = new DhcpInfo();
+ LinkProperties linkProperties = getLinkProperties(netId);
+
+ if (linkProperties != null) {
+ Iterator<LinkAddress> iter = linkProperties.getLinkAddresses().iterator();
+ if (iter.hasNext()) {
+ try {
+ LinkAddress linkAddress = iter.next();
+ dhcpInfo.ipAddress = NetworkUtils.inetAddressToInt(
+ linkAddress.getAddress());
+ dhcpInfo.gateway = NetworkUtils.inetAddressToInt(
+ linkProperties.getGateway());
+ dhcpInfo.netmask = NetworkUtils.prefixLengthToNetmaskInt(
+ linkAddress.getNetworkPrefixLength());
+ Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator();
+ dhcpInfo.dns1 = NetworkUtils.inetAddressToInt(dnsIterator.next());
+ if (dnsIterator.hasNext()) {
+ dhcpInfo.dns2 = NetworkUtils.inetAddressToInt(dnsIterator.next());
+ }
+ } catch (IllegalArgumentException e1) {
+ Log.e(TAG, "IPv6 address cannot be handled " + e1);
+ } catch (NullPointerException e2) {
+ /* Should not happen since a stored static config should be valid */
+ Log.e(TAG, "Invalid partial IP configuration " + e2);
+ }
+ }
+ }
+ return dhcpInfo;
+ }
+
+ /**
* Fetch the proxy properties for a given network id
*/
static ProxyProperties getProxyProperties(int netId) {
- synchronized (sConfiguredNetworks) {
- WifiConfiguration config = sConfiguredNetworks.get(netId);
- if (config != null && config.proxySettings == ProxySettings.STATIC) {
- return new ProxyProperties(config.proxyProperties);
- }
+ LinkProperties linkProperties = getLinkProperties(netId);
+ if (linkProperties != null) {
+ return new ProxyProperties(linkProperties.getHttpProxy());
}
return null;
}
@@ -484,71 +537,75 @@
for(WifiConfiguration config : sConfiguredNetworks.values()) {
boolean writeToFile = false;
- switch (config.ipAssignment) {
- case STATIC:
- out.writeUTF("ipAssignment");
- out.writeUTF(config.ipAssignment.toString());
- out.writeUTF("ipAddress");
- out.writeInt(config.ipConfig.ipAddress);
- out.writeUTF("gateway");
- out.writeInt(config.ipConfig.gateway);
- out.writeUTF("netmask");
- out.writeInt(config.ipConfig.netmask);
- out.writeUTF("dns1");
- out.writeInt(config.ipConfig.dns1);
- out.writeUTF("dns2");
- out.writeInt(config.ipConfig.dns2);
- writeToFile = true;
- break;
- case DHCP:
- out.writeUTF("ipAssignment");
- out.writeUTF(config.ipAssignment.toString());
- writeToFile = true;
- break;
- case UNASSIGNED:
- /* Ignore */
- break;
- default:
- Log.e(TAG, "Ignore invalid ip assignment while writing");
- break;
- }
-
- switch (config.proxySettings) {
- case STATIC:
- out.writeUTF("proxySettings");
- out.writeUTF(config.proxySettings.toString());
- InetSocketAddress proxy = config.proxyProperties.getSocketAddress();
- if (proxy != null) {
- out.writeUTF("proxyHost");
- out.writeUTF(proxy.getHostName());
- out.writeUTF("proxyPort");
- out.writeInt(proxy.getPort());
- String exclusionList = config.proxyProperties.getExclusionList();
- if (exclusionList != null && exclusionList.length() > 0) {
- out.writeUTF("exclusionList");
- out.writeUTF(exclusionList);
+ try {
+ LinkProperties linkProperties = config.linkProperties;
+ switch (config.ipAssignment) {
+ case STATIC:
+ out.writeUTF(IP_ASSIGNMENT_KEY);
+ out.writeUTF(config.ipAssignment.toString());
+ for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) {
+ out.writeUTF(LINK_ADDRESS_KEY);
+ out.writeUTF(linkAddr.getAddress().getHostAddress());
+ out.writeInt(linkAddr.getNetworkPrefixLength());
}
- }
- writeToFile = true;
- break;
- case NONE:
- out.writeUTF("proxySettings");
- out.writeUTF(config.proxySettings.toString());
- writeToFile = true;
- break;
- case UNASSIGNED:
- /* Ignore */
- break;
- default:
- Log.e(TAG, "Ignore invalid proxy settings while writing");
- break;
- }
+ InetAddress gateway = linkProperties.getGateway();
+ if (gateway != null) {
+ out.writeUTF(GATEWAY_KEY);
+ out.writeUTF(gateway.getHostAddress());
+ }
+ for (InetAddress inetAddr : linkProperties.getDnses()) {
+ out.writeUTF(DNS_KEY);
+ out.writeUTF(inetAddr.getHostAddress());
+ }
+ writeToFile = true;
+ break;
+ case DHCP:
+ out.writeUTF(IP_ASSIGNMENT_KEY);
+ out.writeUTF(config.ipAssignment.toString());
+ writeToFile = true;
+ break;
+ case UNASSIGNED:
+ /* Ignore */
+ break;
+ default:
+ Log.e(TAG, "Ignore invalid ip assignment while writing");
+ break;
+ }
- if (writeToFile) {
- out.writeUTF("id");
- out.writeInt(configKey(config));
- out.writeUTF("EOS");
+ switch (config.proxySettings) {
+ case STATIC:
+ ProxyProperties proxyProperties = linkProperties.getHttpProxy();
+ String exclusionList = proxyProperties.getExclusionList();
+ out.writeUTF(PROXY_SETTINGS_KEY);
+ out.writeUTF(config.proxySettings.toString());
+ out.writeUTF(PROXY_HOST_KEY);
+ out.writeUTF(proxyProperties.getSocketAddress().getHostName());
+ out.writeUTF(PROXY_PORT_KEY);
+ out.writeInt(proxyProperties.getSocketAddress().getPort());
+ out.writeUTF(EXCLUSION_LIST_KEY);
+ out.writeUTF(exclusionList);
+ writeToFile = true;
+ break;
+ case NONE:
+ out.writeUTF(PROXY_SETTINGS_KEY);
+ out.writeUTF(config.proxySettings.toString());
+ writeToFile = true;
+ break;
+ case UNASSIGNED:
+ /* Ignore */
+ break;
+ default:
+ Log.e(TAG, "Ignore invalid proxy settings while writing");
+ break;
+ }
+ if (writeToFile) {
+ out.writeUTF(ID_KEY);
+ out.writeInt(configKey(config));
+ }
+ } catch (NullPointerException e) {
+ Log.e(TAG, "Failure in writing " + config.linkProperties + e);
}
+ out.writeUTF(EOS);
}
}
@@ -578,8 +635,8 @@
while (true) {
int id = -1;
IpAssignment ipAssignment = IpAssignment.UNASSIGNED;
- DhcpInfo ipConfig = new DhcpInfo();
ProxySettings proxySettings = ProxySettings.UNASSIGNED;
+ LinkProperties linkProperties = new LinkProperties();
String proxyHost = null;
int proxyPort = -1;
String exclusionList = null;
@@ -587,32 +644,34 @@
do {
key = in.readUTF();
- if (key.equals("id")) {
- id = in.readInt();
- } else if (key.equals("ipAssignment")) {
- ipAssignment = IpAssignment.valueOf(in.readUTF());
- } else if (key.equals("ipAddress")) {
- ipConfig.ipAddress = in.readInt();
- } else if (key.equals("gateway")) {
- ipConfig.gateway = in.readInt();
- } else if (key.equals("netmask")) {
- ipConfig.netmask = in.readInt();
- } else if (key.equals("dns1")) {
- ipConfig.dns1 = in.readInt();
- } else if (key.equals("dns2")) {
- ipConfig.dns2 = in.readInt();
- } else if (key.equals("proxySettings")) {
- proxySettings = ProxySettings.valueOf(in.readUTF());
- } else if (key.equals("proxyHost")) {
- proxyHost = in.readUTF();
- } else if (key.equals("proxyPort")) {
- proxyPort = in.readInt();
- } else if (key.equals("exclusionList")) {
- exclusionList = in.readUTF();
- } else if (key.equals("EOS")) {
- break;
- } else {
- Log.e(TAG, "Ignore unknown key " + key + "while reading");
+ try {
+ if (key.equals(ID_KEY)) {
+ id = in.readInt();
+ } else if (key.equals(IP_ASSIGNMENT_KEY)) {
+ ipAssignment = IpAssignment.valueOf(in.readUTF());
+ } else if (key.equals(LINK_ADDRESS_KEY)) {
+ LinkAddress linkAddr = new LinkAddress(InetAddress.getByName(
+ in.readUTF()), in.readInt());
+ linkProperties.addLinkAddress(linkAddr);
+ } else if (key.equals(GATEWAY_KEY)) {
+ linkProperties.setGateway(InetAddress.getByName(in.readUTF()));
+ } else if (key.equals(DNS_KEY)) {
+ linkProperties.addDns(InetAddress.getByName(in.readUTF()));
+ } else if (key.equals(PROXY_SETTINGS_KEY)) {
+ proxySettings = ProxySettings.valueOf(in.readUTF());
+ } else if (key.equals(PROXY_HOST_KEY)) {
+ proxyHost = in.readUTF();
+ } else if (key.equals(PROXY_PORT_KEY)) {
+ proxyPort = in.readInt();
+ } else if (key.equals(EXCLUSION_LIST_KEY)) {
+ exclusionList = in.readUTF();
+ } else if (key.equals(EOS)) {
+ break;
+ } else {
+ Log.e(TAG, "Ignore unknown key " + key + "while reading");
+ }
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "Ignore invalid address while reading" + e);
}
} while (true);
@@ -624,11 +683,9 @@
if (config == null) {
Log.e(TAG, "configuration found for missing network, ignored");
} else {
+ config.linkProperties = linkProperties;
switch (ipAssignment) {
case STATIC:
- config.ipAssignment = ipAssignment;
- config.ipConfig = ipConfig;
- break;
case DHCP:
config.ipAssignment = ipAssignment;
break;
@@ -647,7 +704,7 @@
proxyProperties.setSocketAddress(
new InetSocketAddress(proxyHost, proxyPort));
proxyProperties.setExclusionList(exclusionList);
- config.proxyProperties = proxyProperties;
+ linkProperties.setHttpProxy(proxyProperties);
break;
case NONE:
config.proxySettings = proxySettings;
@@ -662,11 +719,12 @@
}
}
} else {
- Log.e(TAG,"Missing id while parsing configuration");
+ Log.e(TAG, "Missing id while parsing configuration");
}
}
+ } catch (EOFException ignore) {
} catch (IOException e) {
- Log.e(TAG, "Error parsing configuration");
+ Log.e(TAG, "Error parsing configuration" + e);
} finally {
if (in != null) {
try {
@@ -894,63 +952,140 @@
/* Compare current and new configuration and write to file on change */
private static void writeIpAndProxyConfigurationsOnChange(WifiConfiguration currentConfig,
WifiConfiguration newConfig) {
- boolean newNetwork = (newConfig.networkId == INVALID_NETWORK_ID);
- boolean writeConfigToFile = false;
+ boolean ipChanged = false;
+ boolean proxyChanged = false;
+ LinkProperties linkProperties = new LinkProperties();
- if (newConfig.ipAssignment != IpAssignment.UNASSIGNED) {
- if (newNetwork ||
- (currentConfig.ipAssignment != newConfig.ipAssignment) ||
- (currentConfig.ipConfig.ipAddress != newConfig.ipConfig.ipAddress) ||
- (currentConfig.ipConfig.gateway != newConfig.ipConfig.gateway) ||
- (currentConfig.ipConfig.netmask != newConfig.ipConfig.netmask) ||
- (currentConfig.ipConfig.dns1 != newConfig.ipConfig.dns1) ||
- (currentConfig.ipConfig.dns2 != newConfig.ipConfig.dns2)) {
- currentConfig.ipAssignment = newConfig.ipAssignment;
- currentConfig.ipConfig = newConfig.ipConfig;
- writeConfigToFile = true;
+ switch (newConfig.ipAssignment) {
+ case STATIC:
+ Collection<LinkAddress> currentLinkAddresses = currentConfig.linkProperties
+ .getLinkAddresses();
+ Collection<LinkAddress> newLinkAddresses = newConfig.linkProperties
+ .getLinkAddresses();
+ Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses();
+ Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses();
+ InetAddress currentGateway = currentConfig.linkProperties.getGateway();
+ InetAddress newGateway = newConfig.linkProperties.getGateway();
+
+ boolean linkAddressesDiffer = !currentLinkAddresses.containsAll(newLinkAddresses) ||
+ (currentLinkAddresses.size() != newLinkAddresses.size());
+ boolean dnsesDiffer = !currentDnses.containsAll(newDnses) ||
+ (currentDnses.size() != newDnses.size());
+ boolean gatewaysDiffer = (currentGateway == null) ||
+ !currentGateway.equals(newGateway);
+
+ if ((currentConfig.ipAssignment != newConfig.ipAssignment) ||
+ linkAddressesDiffer ||
+ dnsesDiffer ||
+ gatewaysDiffer) {
+ ipChanged = true;
+ }
+ break;
+ case DHCP:
+ if (currentConfig.ipAssignment != newConfig.ipAssignment) {
+ ipChanged = true;
+ }
+ break;
+ case UNASSIGNED:
+ /* Ignore */
+ break;
+ default:
+ Log.e(TAG, "Ignore invalid ip assignment during write");
+ break;
+ }
+
+ switch (newConfig.proxySettings) {
+ case STATIC:
+ InetSocketAddress newSockAddr = null;
+ String newExclusionList = null;
+ InetSocketAddress currentSockAddr = null;
+ String currentExclusionList = null;
+
+ ProxyProperties newHttpProxy = newConfig.linkProperties.getHttpProxy();
+ if (newHttpProxy != null) {
+ newSockAddr = newHttpProxy.getSocketAddress();
+ newExclusionList = newHttpProxy.getExclusionList();
+ }
+
+ ProxyProperties currentHttpProxy = currentConfig.linkProperties.getHttpProxy();
+ if (currentHttpProxy != null) {
+ currentSockAddr = currentHttpProxy.getSocketAddress();
+ currentExclusionList = currentHttpProxy.getExclusionList();
+ }
+
+ boolean socketAddressDiffers = false;
+ boolean exclusionListDiffers = false;
+
+ if (newSockAddr != null && currentSockAddr != null ) {
+ socketAddressDiffers = !currentSockAddr.equals(newSockAddr);
+ } else if (newSockAddr != null || currentSockAddr != null) {
+ socketAddressDiffers = true;
+ }
+
+ if (newExclusionList != null && currentExclusionList != null) {
+ exclusionListDiffers = !currentExclusionList.equals(newExclusionList);
+ } else if (newExclusionList != null || currentExclusionList != null) {
+ exclusionListDiffers = true;
+ }
+
+ if ((currentConfig.proxySettings != newConfig.proxySettings) ||
+ socketAddressDiffers ||
+ exclusionListDiffers) {
+ proxyChanged = true;
+ }
+ break;
+ case NONE:
+ if (currentConfig.proxySettings != newConfig.proxySettings) {
+ proxyChanged = true;
+ }
+ break;
+ case UNASSIGNED:
+ /* Ignore */
+ break;
+ default:
+ Log.e(TAG, "Ignore invalid proxy configuration during write");
+ break;
+ }
+
+ if (!ipChanged) {
+ addIpSettingsFromConfig(linkProperties, currentConfig);
+ } else {
+ currentConfig.ipAssignment = newConfig.ipAssignment;
+ addIpSettingsFromConfig(linkProperties, newConfig);
+ Log.d(TAG, "IP config changed SSID = " + currentConfig.SSID + " linkProperties: " +
+ linkProperties.toString());
+ }
+
+
+ if (!proxyChanged) {
+ linkProperties.setHttpProxy(currentConfig.linkProperties.getHttpProxy());
+ } else {
+ currentConfig.proxySettings = newConfig.proxySettings;
+ linkProperties.setHttpProxy(newConfig.linkProperties.getHttpProxy());
+ Log.d(TAG, "proxy changed SSID = " + currentConfig.SSID);
+ if (linkProperties.getHttpProxy() != null) {
+ Log.d(TAG, " proxyProperties: " + linkProperties.getHttpProxy().toString());
}
}
- if (newConfig.proxySettings != ProxySettings.UNASSIGNED) {
- InetSocketAddress newSockAddr = newConfig.proxyProperties.getSocketAddress();
- String newExclusionList = newConfig.proxyProperties.getExclusionList();
-
- InetSocketAddress currentSockAddr = currentConfig.proxyProperties.getSocketAddress();
- String currentExclusionList = currentConfig.proxyProperties.getExclusionList();
-
- boolean socketAddressDiffers = false;
- boolean exclusionListDiffers = false;
-
- if (newSockAddr != null && currentSockAddr != null ) {
- socketAddressDiffers = !currentSockAddr.equals(newSockAddr);
- } else if (newSockAddr != null || currentSockAddr != null) {
- socketAddressDiffers = true;
- }
-
- if (newExclusionList != null && currentExclusionList != null) {
- exclusionListDiffers = currentExclusionList.equals(newExclusionList);
- } else if (newExclusionList != null || currentExclusionList != null) {
- exclusionListDiffers = true;
- }
-
- if (newNetwork ||
- (currentConfig.proxySettings != newConfig.proxySettings) ||
- socketAddressDiffers ||
- exclusionListDiffers) {
- currentConfig.proxySettings = newConfig.proxySettings;
- currentConfig.proxyProperties = newConfig.proxyProperties;
- Log.d(TAG, "proxy change SSID = " + currentConfig.SSID + " proxyProperties: " +
- currentConfig.proxyProperties.toString());
- writeConfigToFile = true;
- }
- }
-
- if (writeConfigToFile) {
+ if (ipChanged || proxyChanged) {
+ currentConfig.linkProperties = linkProperties;
writeIpAndProxyConfigurations();
sendConfigChangeBroadcast();
}
}
+ private static void addIpSettingsFromConfig(LinkProperties linkProperties,
+ WifiConfiguration config) {
+ for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) {
+ linkProperties.addLinkAddress(linkAddr);
+ }
+ linkProperties.setGateway(config.linkProperties.getGateway());
+ for (InetAddress dns : config.linkProperties.getDnses()) {
+ linkProperties.addDns(dns);
+ }
+ }
+
/**
* Read the variables from the supplicant daemon that are needed to
* fill in the WifiConfiguration object.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index c4a1310..d5fb63e 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -16,8 +16,7 @@
package android.net.wifi;
-import android.net.DhcpInfo;
-import android.net.ProxyProperties;
+import android.net.LinkProperties;
import android.os.Parcelable;
import android.os.Parcel;
@@ -303,7 +302,7 @@
*/
public enum IpAssignment {
/* Use statically configured IP settings. Configuration can be accessed
- * with ipConfig */
+ * with linkProperties */
STATIC,
/* Use dynamically configured IP settigns */
DHCP,
@@ -315,10 +314,6 @@
* @hide
*/
public IpAssignment ipAssignment;
- /**
- * @hide
- */
- public DhcpInfo ipConfig;
/**
* @hide
@@ -328,7 +323,7 @@
* should be cleared. */
NONE,
/* Use statically configured proxy. Configuration can be accessed
- * with proxyProperties */
+ * with linkProperties */
STATIC,
/* no proxy details are assigned, this is used to indicate
* that any existing proxy settings should be retained */
@@ -341,7 +336,7 @@
/**
* @hide
*/
- public ProxyProperties proxyProperties;
+ public LinkProperties linkProperties;
public WifiConfiguration() {
networkId = INVALID_NETWORK_ID;
@@ -361,9 +356,8 @@
field.setValue(null);
}
ipAssignment = IpAssignment.UNASSIGNED;
- ipConfig = new DhcpInfo();
proxySettings = ProxySettings.UNASSIGNED;
- proxyProperties = new ProxyProperties();
+ linkProperties = new LinkProperties();
}
public String toString() {
@@ -445,17 +439,13 @@
if (value != null) sbuf.append(value);
}
sbuf.append('\n');
- if (ipAssignment == IpAssignment.STATIC) {
- sbuf.append(" ").append("Static IP configuration:").append('\n');
- sbuf.append(" ").append(ipConfig);
- }
- sbuf.append('\n');
+ sbuf.append("IP assignment: " + ipAssignment.toString());
+ sbuf.append("\n");
+ sbuf.append("Proxy settings: " + proxySettings.toString());
+ sbuf.append("\n");
+ sbuf.append(linkProperties.toString());
+ sbuf.append("\n");
- if (proxySettings == ProxySettings.STATIC) {
- sbuf.append(" ").append("Proxy configuration:").append('\n');
- sbuf.append(" ").append(proxyProperties);
- }
- sbuf.append('\n');
return sbuf.toString();
}
@@ -521,9 +511,8 @@
enterpriseFields[i].setValue(source.enterpriseFields[i].value());
}
ipAssignment = source.ipAssignment;
- ipConfig = new DhcpInfo(source.ipConfig);
proxySettings = source.proxySettings;
- proxyProperties = new ProxyProperties(source.proxyProperties);
+ linkProperties = new LinkProperties(source.linkProperties);
}
}
@@ -550,15 +539,8 @@
dest.writeString(field.value());
}
dest.writeString(ipAssignment.name());
- dest.writeInt(ipConfig.ipAddress);
- dest.writeInt(ipConfig.netmask);
- dest.writeInt(ipConfig.gateway);
- dest.writeInt(ipConfig.dns1);
- dest.writeInt(ipConfig.dns2);
- dest.writeInt(ipConfig.serverAddress);
- dest.writeInt(ipConfig.leaseDuration);
dest.writeString(proxySettings.name());
- dest.writeParcelable(proxyProperties, flags);
+ dest.writeParcelable(linkProperties, flags);
}
/** Implement the Parcelable interface {@hide} */
@@ -587,15 +569,8 @@
}
config.ipAssignment = IpAssignment.valueOf(in.readString());
- config.ipConfig.ipAddress = in.readInt();
- config.ipConfig.netmask = in.readInt();
- config.ipConfig.gateway = in.readInt();
- config.ipConfig.dns1 = in.readInt();
- config.ipConfig.dns2 = in.readInt();
- config.ipConfig.serverAddress = in.readInt();
- config.ipConfig.leaseDuration = in.readInt();
config.proxySettings = ProxySettings.valueOf(in.readString());
- config.proxyProperties = in.readParcelable(null);
+ config.linkProperties = in.readParcelable(null);
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 572abc0..efd0e0a 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1253,25 +1253,22 @@
}
private void configureLinkProperties() {
-
+ if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+ mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId);
+ } else {
+ // TODO - fix this for v6
+ synchronized (mDhcpInfo) {
+ mLinkProperties.addLinkAddress(new LinkAddress(
+ NetworkUtils.intToInetAddress(mDhcpInfo.ipAddress),
+ NetworkUtils.intToInetAddress(mDhcpInfo.netmask)));
+ mLinkProperties.setGateway(NetworkUtils.intToInetAddress(mDhcpInfo.gateway));
+ mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns1));
+ mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns2));
+ }
+ mLinkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
+ }
mLinkProperties.setInterfaceName(mInterfaceName);
-
- // TODO - fix this for v6
- synchronized (mDhcpInfo) {
- mLinkProperties.addLinkAddress(new LinkAddress(
- NetworkUtils.intToInetAddress(mDhcpInfo.ipAddress),
- NetworkUtils.intToInetAddress(mDhcpInfo.netmask)));
- mLinkProperties.setGateway(NetworkUtils.intToInetAddress(mDhcpInfo.gateway));
- mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns1));
- mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns2));
- }
-
- ProxyProperties proxyProperties = WifiConfigStore.getProxyProperties(mLastNetworkId);
- if (proxyProperties != null) {
- mLinkProperties.setHttpProxy(proxyProperties);
- Log.d(TAG, "netId=" + mLastNetworkId + " proxy configured: "
- + proxyProperties.toString());
- }
+ Log.d(TAG, "netId=" + mLastNetworkId + " Link configured: " + mLinkProperties.toString());
}
private int getMaxDhcpRetries() {
@@ -2571,7 +2568,6 @@
mLastSignalLevel = -1; // force update of signal strength
synchronized (mDhcpInfo) {
mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
- Log.d(TAG, "IP configuration: " + mDhcpInfo);
}
configureLinkProperties();
setDetailedState(DetailedState.CONNECTED);